From a5325a95de5b5151009b9e566995f1d88ff2e359 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Wed, 21 Feb 2024 12:50:07 +0100 Subject: [PATCH 001/140] mac: fix ul rlf detector + set log to warnings: Signed-off-by: Carlo Galiotto --- lib/mac/mac_sched/rlf_detector.h | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/mac/mac_sched/rlf_detector.h b/lib/mac/mac_sched/rlf_detector.h index 083b364823..50c4d00186 100644 --- a/lib/mac/mac_sched/rlf_detector.h +++ b/lib/mac/mac_sched/rlf_detector.h @@ -66,12 +66,12 @@ class rlf_detector void handle_ack(du_ue_index_t ue_index, du_cell_index_t cell_index, bool ack) { - handle_ack_common(ue_index, cell_index, ack, 0); + handle_ack_common(ue_index, cell_index, ack, /* is_dl=*/true); } void handle_crc(du_ue_index_t ue_index, du_cell_index_t cell_index, bool crc) { - handle_ack_common(ue_index, cell_index, crc, 1); + handle_ack_common(ue_index, cell_index, crc, /* is_dl=*/false); } void handle_csi(du_ue_index_t ue_index, du_cell_index_t cell_index, bool csi_decoded) @@ -89,7 +89,7 @@ class rlf_detector if (current_count == max_consecutive_kos[cell_index].max_consecutive_csi_dtx) { std::lock_guard lock(u.notifier_mutex); if (u.notifier != nullptr) { - logger.info("ue={}: RLF detected. Cause: {} consecutive undecoded CSIs", ue_index, current_count); + logger.warning("ue={}: RLF detected. Cause: {} consecutive undecoded CSIs", ue_index, current_count); // Notify upper layers. u.notifier->on_rlf_detected(); @@ -110,25 +110,26 @@ class rlf_detector } private: - void handle_ack_common(du_ue_index_t ue_index, du_cell_index_t cell_index, bool ack, unsigned count_index) + void handle_ack_common(du_ue_index_t ue_index, du_cell_index_t cell_index, bool ack, bool is_dl) { srsran_assert(ue_index < MAX_NOF_DU_UES, "Invalid ue_index={}", ue_index); - auto& u = ues[ue_index]; + auto& u = ues[ue_index]; + const unsigned count_index = is_dl ? 0 : 1; if (ack) { u.ko_counters[count_index].store(0, std::memory_order::memory_order_relaxed); } else { unsigned current_count = u.ko_counters[count_index].fetch_add(1, std::memory_order::memory_order_relaxed) + 1; // Note: We use == instead of <= to ensure only one notification is sent. - const unsigned max_counter = count_index == 0 ? max_consecutive_kos[cell_index].max_consecutive_dl_kos - : max_consecutive_kos[cell_index].max_consecutive_csi_dtx; + const unsigned max_counter = is_dl ? max_consecutive_kos[cell_index].max_consecutive_dl_kos + : max_consecutive_kos[cell_index].max_consecutive_ul_kos; if (current_count == max_counter) { std::lock_guard lock(u.notifier_mutex); if (u.notifier != nullptr) { - logger.info("ue={}: RLF detected. Cause: {} consecutive {} KOs.", - ue_index, - current_count, - count_index == 0 ? "HARQ-ACK" : "CRC"); + logger.warning("ue={}: RLF detected. Cause: {} consecutive {} KOs.", + ue_index, + current_count, + is_dl ? "HARQ-ACK" : "CRC"); // Notify upper layers. u.notifier->on_rlf_detected(); From eba993c009774a160a4bdf5a648e6ea86986360f Mon Sep 17 00:00:00 2001 From: sauka Date: Fri, 23 Feb 2024 12:17:30 +0200 Subject: [PATCH 002/140] ofh: inline utility functions used in compression --- lib/ofh/compression/CMakeLists.txt | 11 +- lib/ofh/compression/packing_utils_avx2.cpp | 229 ------------------ lib/ofh/compression/packing_utils_avx2.h | 216 ++++++++++++++++- lib/ofh/compression/packing_utils_avx512.cpp | 207 ---------------- lib/ofh/compression/packing_utils_avx512.h | 189 ++++++++++++++- lib/ofh/compression/packing_utils_neon.cpp | 146 ----------- lib/ofh/compression/packing_utils_neon.h | 132 +++++++++- .../ofh/ofh_compression_benchmark.cpp | 2 +- 8 files changed, 532 insertions(+), 600 deletions(-) delete mode 100644 lib/ofh/compression/packing_utils_avx2.cpp delete mode 100644 lib/ofh/compression/packing_utils_avx512.cpp delete mode 100644 lib/ofh/compression/packing_utils_neon.cpp diff --git a/lib/ofh/compression/CMakeLists.txt b/lib/ofh/compression/CMakeLists.txt index 96539c3fed..7c2472f985 100644 --- a/lib/ofh/compression/CMakeLists.txt +++ b/lib/ofh/compression/CMakeLists.txt @@ -17,23 +17,18 @@ set(SOURCES iq_decompressor_selector.cpp) if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64") - list(APPEND SOURCES packing_utils_avx2.cpp + list(APPEND SOURCES iq_compression_bfp_avx2.cpp - packing_utils_avx512.cpp iq_compression_bfp_avx512.cpp iq_compression_none_avx512.cpp) - set_source_files_properties(packing_utils_avx2.cpp PROPERTIES COMPILE_OPTIONS "-mavx2;") set_source_files_properties(iq_compression_bfp_avx2.cpp PROPERTIES COMPILE_OPTIONS "-mavx2;") - set_source_files_properties(packing_utils_avx512.cpp PROPERTIES - COMPILE_OPTIONS "-mavx512f;-mavx512bw;-mavx512vl;-mavx512dq;") set_source_files_properties(iq_compression_bfp_avx512.cpp PROPERTIES - COMPILE_OPTIONS "-mavx512f;-mavx512bw;-mavx512vl;-mavx512cd;") + COMPILE_OPTIONS "-mavx512f;-mavx512bw;-mavx512vl;-mavx512cd;-mavx512dq;") set_source_files_properties(iq_compression_none_avx512.cpp PROPERTIES - COMPILE_OPTIONS "-mavx512f;-mavx512bw;-mavx512vl;") + COMPILE_OPTIONS "-mavx512f;-mavx512bw;-mavx512vl;-mavx512dq;") endif (${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64") if (HAVE_NEON) - list(APPEND SOURCES packing_utils_neon.cpp) list(APPEND SOURCES iq_compression_bfp_neon.cpp) endif (HAVE_NEON) diff --git a/lib/ofh/compression/packing_utils_avx2.cpp b/lib/ofh/compression/packing_utils_avx2.cpp deleted file mode 100644 index 42b00e0169..0000000000 --- a/lib/ofh/compression/packing_utils_avx2.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/* - * - * Copyright 2021-2024 Software Radio Systems Limited - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the distribution. - * - */ - -#include "packing_utils_avx2.h" -#include "srsran/adt/span.h" -#include "srsran/support/error_handling.h" - -using namespace srsran; -using namespace ofh; - -/// Number of bytes used by 1 packed resource block with IQ samples compressed to 9 bits. -static constexpr unsigned BYTES_PER_PRB_9BIT_COMPRESSION = 27; - -bool mm256::iq_width_packing_supported(unsigned iq_width) -{ - return iq_width == 9; -} - -/// \brief Packs 16bit IQ samples in one AVX2 register using 9bit big-endian format. -/// -/// \param[in] cmp_data_epi16 AVX2 register storing 16bit IQ samples. -/// \return An AVX2 register containing 18 packed bytes. -/// -/// \note Each 128bit lane of the input contains eight I and Q values, with each value consisting of 9 bits of data (the -/// LSB ones) and 7 bits of padding. The function packs the eight IQ samples (only the data bits, discarding the -/// padding) into the first 9 bytes of the respective 128bit lane of the output register (the remaining 7 bytes are -/// padding). Thus, the return value contains 18 packed data bytes in total. -static __m256i pack_avx2_register_9b_be(__m256i cmp_data_epi16) -{ - // Input IQ samples need to be shifted in order to align bits before final packing. - // 0: i0 0 0 0 0 0 0 0 i8 i7 i6 i5 i4 i3 i2 i1 <- rotate right by 1 (shift left by 7, swap bytes later) - // 1: 0 q8 q7 q6 q5 q4 q3 q2 q1 q0 0 0 0 0 0 0 <- shift left by 6 - // 2: 0 0 i8 i7 i6 i5 i4 i3 i2 i1 i0 0 0 0 0 0 <- shift left by 5 - // 3: 0 0 0 q8 q7 q6 q5 q4 q3 q2 q1 q0 0 0 0 0 <- shift left by 4 - // 4: 0 0 0 0 i8 i7 i6 i5 i4 i3 i2 i1 i0 0 0 0 <- shift left by 3 - // 5: 0 0 0 0 0 q8 q7 q6 q5 q4 q3 q2 q1 q0 0 0 <- shift left by 2 - // 6: 0 0 0 0 0 0 i8 i7 i6 i5 i4 i3 i2 i1 i0 0 <- shift left by 1 - // 7: 0 0 0 0 0 0 0 q8 q7 q6 q5 q4 q3 q2 q1 q0 <- no shift - // ... the same pattern ... - // - // Note, AVX2 only allows shifting 32bit words using vector of indexes, so we do it twice. - const __m256i shift_0_epi32 = _mm256_setr_epi32(7, 5, 3, 1, 7, 5, 3, 1); - const __m256i shift_1_epi32 = _mm256_setr_epi32(6, 4, 2, 0, 6, 4, 2, 0); - __m256i cmp_data_sh0_epi16 = _mm256_sllv_epi32(cmp_data_epi16, shift_0_epi32); - __m256i cmp_data_sh1_epi16 = _mm256_sllv_epi32(cmp_data_epi16, shift_1_epi32); - // Mask 16bit words to keep only 9 shifted bits. - const __m256i mask_even_epi16 = - _mm256_setr_epi32(0x0000ff80, 0x00003fe0, 0x00000ff8, 0x000003fe, 0x0000ff80, 0x00003fe0, 0x00000ff8, 0x000003fe); - const __m256i mask_odd_epi16 = - _mm256_setr_epi32(0x7fc00000, 0x1ff00000, 0x07fc0000, 0x01ff0000, 0x7fc00000, 0x1ff00000, 0x07fc0000, 0x01ff0000); - cmp_data_sh0_epi16 = _mm256_and_si256(cmp_data_sh0_epi16, mask_even_epi16); - cmp_data_sh1_epi16 = _mm256_and_si256(cmp_data_sh1_epi16, mask_odd_epi16); - - // Merge two vectors to get vector of shifted IQ samples as explained above. - __m256i cmp_data_shifted_epi16 = _mm256_or_si256(cmp_data_sh0_epi16, cmp_data_sh1_epi16); - - // Shuffle it and create two new vectors that can be OR'ed to produce the final result. - __m256i cmp_data_v0_epi16 = _mm256_shuffle_epi8( - cmp_data_shifted_epi16, - _mm256_setr_epi64x(0x0c0a0806040200ff, 0xffffffffffffff0e, 0x0c0a0806040200ff, 0xffffffffffffff0e)); - __m256i cmp_data_v1_epi16 = _mm256_shuffle_epi8( - cmp_data_shifted_epi16, - _mm256_setr_epi64x(0x0f0d0b0907050301, 0xffffffffffffffff, 0x0f0d0b0907050301, 0xffffffffffffffff)); - // Perform 'bitwise OR' and return the result. - return _mm256_or_si256(cmp_data_v0_epi16, cmp_data_v1_epi16); -} - -/// \brief Packs 16bit IQ values of the two input RBs using 9bit big-endian format. -/// -/// The following diagram shows the input format. Here RBx stands for one unique RE (pair of IQ samples, 32 bits long) -/// pertaining to a respective RB): -/// | | | | | | -/// | ----- | ------- | ------- | ------- | ------- | -/// | \c r0: | RB0 RB0 | RB0 RB0 | RB0 RB0 | RB0 RB0 | -/// | \c r1: | RB0 RB0 | RB0 RB0 | RB1 RB1 | RB1 RB1 | -/// | \c r2: | RB1 RB1 | RB1 RB1 | RB1 RB1 | RB1 RB1 | -/// -/// \param[out] c_prbs Span of two compressed PRBs. -/// \param[in] r0 AVX2 register storing 16bit IQ samples of the first RB. -/// \param[in] r1 AVX2 register storing 16bit IQ samples of the first and second RB. -/// \param[in] r2 AVX2 register storing 16bit IQ samples of the second RB. -static void avx2_pack_prbs_9b_big_endian(span c_prbs, __m256i r0, __m256i r1, __m256i r2) -{ - srsran_assert(c_prbs.size() == 2, "Output span must contain 2 resource blocks"); - - // Returns first 18 packed bytes out of 27 for the first RB (9 bytes in each 128bit lane - same applies below). - __m256i reg0_packed_epi8 = pack_avx2_register_9b_be(r0); - // Returns last 9 packed bytes out of 27 for the first RB and first 9 packed bytes for the second RB. - __m256i reg1_packed_epi8 = pack_avx2_register_9b_be(r1); - // Returns last 18 packed bytes out of 27 for the second RB. - __m256i reg2_packed_epi8 = pack_avx2_register_9b_be(r2); - - // AVX2 doesn't provide instruction to store specific bytes of the lanes using a mask, so we create new vectors, - // and use a regular store intrinsic. - // - // Next example explains the bytes permutations performed below for each RB to group its packed IQs. - // r0: {0xe959c2834776bd64, 0x8b, 0xdc0c7ca5b0ab3a56, 0x31} - // r1: {0xb1e93964f248fe46, 0xaf, 0x4f0f368e76fc7a9e, 0x12} - // r0_tmp0: {0xe959c2834776bd64, 0x000000000000008b, 0x0c7ca5b0ab3a5600, 0x00000000000031dc} - // r1_tmp0: {0x3964f248fe460000, 0x0000000000afb1e9, 0x0000000000000000, 0x0000000000000000} - // r0_tmp1: {0xe959c2834776bd64, 0x0c7ca5b0ab3a5600, 0x00000000000031dc, 0x0000000000000000} - // r1_tmp1: {0x0000000000000000, 0x0000000000000000, 0x3964f248fe460000, 0x0000000000afb1e9} - // rb0_tmp0: {0xe959c2834776bd64, 0x0c7ca5b0ab3a568b, XXXXXXXXXXXXXXXXXX, XXXXXXXXXXXXXXXXXX} - // rb0_tmp1: {XXXXXXXXXXXXXXXXXX, XXXXXXXXXXXXXXXXXX, 0x3964f248fe4631dc, 0x0000000000afb1e9} - // select 64bit words between rb0_tmp0 and rb0_tmp1: - // rb0: {0xe959c2834776bd64, 0x0c7ca5b0ab3a568b, 0x3964f248fe4631dc, 0x0000000000afb1e9} - - // Pack the first input RB. - const __m256i shuffle_mask_0 = - _mm256_setr_epi64x(0x0706050403020100, 0x0f0e0d0c0b0a0908, 0x06050403020100ff, 0xffffffffffff0807); - __m256i reg0_tmp0_epi8 = _mm256_shuffle_epi8(reg0_packed_epi8, shuffle_mask_0); - - const __m256i shuffle_mask_1 = - _mm256_setr_epi64x(0x050403020100ffff, 0xffffffffff080706, 0xffffffffffffffff, 0xffffffffffffffff); - __m256i reg1_tmp0_epi8 = _mm256_shuffle_epi8(reg1_packed_epi8, shuffle_mask_1); - - __m256i reg0_tmp1_epi8 = _mm256_permutevar8x32_epi32(reg0_tmp0_epi8, _mm256_setr_epi32(0, 1, 4, 5, 6, 7, 3, 3)); - __m256i reg1_tmp1_epi8 = _mm256_permute4x64_epi64(reg1_tmp0_epi8, 0b01001110); - - const __m256i sel_mask_0_epi8 = - _mm256_setr_epi64x(0x0000000000000000, 0x0000000000000000, 0xffffffffffffffff, 0xffffffffffffffff); - __m256i prb0_tmp0_epi8 = _mm256_or_si256(reg0_tmp0_epi8, reg0_tmp1_epi8); - __m256i prb0_tmp1_epi8 = _mm256_or_si256(reg0_tmp1_epi8, reg1_tmp1_epi8); - __m256i prb0_epi8 = _mm256_blendv_epi8(prb0_tmp0_epi8, prb0_tmp1_epi8, sel_mask_0_epi8); - - // Pack the second input RB. - const __m256i shuffle_mask_2 = - _mm256_setr_epi64x(0xffffffffffff0807, 0x06050403020100ff, 0x050403020100ffff, 0xffffffffff080706); - __m256i reg1_tmp2_epi8 = _mm256_permutevar8x32_epi32(reg1_packed_epi8, _mm256_setr_epi32(4, 5, 6, 7, 3, 3, 3, 3)); - __m256i reg2_tmp0_epi8 = _mm256_shuffle_epi8(reg2_packed_epi8, shuffle_mask_2); - __m256i reg2_tmp1_epi8 = _mm256_permutevar8x32_epi32(reg2_tmp0_epi8, _mm256_setr_epi32(1, 1, 2, 3, 0, 1, 6, 7)); - - const __m256i sel_mask_1_epi8 = - _mm256_setr_epi64x(0x0000000000000000, 0x0000000000000000, 0xffffffffffffffff, 0xffffffffffffffff); - __m256i prb1_tmp0_epi8 = _mm256_or_si256(reg1_tmp2_epi8, reg2_tmp1_epi8); - __m256i prb1_tmp1_epi8 = _mm256_or_si256(reg2_tmp0_epi8, reg2_tmp1_epi8); - __m256i prb1_epi8 = _mm256_blendv_epi8(prb1_tmp0_epi8, prb1_tmp1_epi8, sel_mask_1_epi8); - - // Write resource blocks to the memory. - _mm256_storeu_si256(reinterpret_cast<__m256i*>(c_prbs[0].get_byte_buffer().data()), prb0_epi8); - c_prbs[0].set_stored_size(BYTES_PER_PRB_9BIT_COMPRESSION); - - _mm256_storeu_si256(reinterpret_cast<__m256i*>(c_prbs[1].get_byte_buffer().data()), prb1_epi8); - c_prbs[1].set_stored_size(BYTES_PER_PRB_9BIT_COMPRESSION); -} - -void mm256::pack_prbs_big_endian(span c_prbs, __m256i r0, __m256i r1, __m256i r2, unsigned iq_width) -{ - switch (iq_width) { - case 9: - avx2_pack_prbs_9b_big_endian(c_prbs, r0, r1, r2); - break; - default: - report_fatal_error("Unsupported bit width"); - } -} - -/// \brief Unpacks packed 9bit IQ samples stored as bytes in big-endian format to an array of 16bit signed values. -/// -/// \param[out] unpacked_iq_data A span of 16bit integers, corresponding to \c NOF_CARRIERS_PER_RB unpacked IQ pairs. -/// \param[in] packed_data A span of 27 packed bytes. -/// -/// \note The \c unpacked_iq_data parameter should be sized to store 32 output IQ samples: it is 24 IQ samples of one RB -/// rounded up to 32-byte boundary required by AVX2 intrinsics. -static void unpack_prb_9b_be(span unpacked_iq_data, span packed_data) -{ - constexpr size_t avx2_size_short_words = 16; - srsran_assert(unpacked_iq_data.size() >= avx2_size_short_words * 2, "Wrong unpacked data span size"); - - // Load input, 27 bytes (fits in one AVX2 register). - __m256i packed_data_epi8 = _mm256_loadu_si256(reinterpret_cast(packed_data.data())); - - // Duplicate input words (it is required since below in the code every byte will be used twice: - // to provide MSB bits of the current IQ sample and LSB bits of the previous IQ sample). - __m256i packed_data_0_epi8 = _mm256_permute4x64_epi64(packed_data_epi8, 0b10010100); - __m256i packed_data_1_epi8 = _mm256_permute4x64_epi64(packed_data_epi8, 0b00001110); - - // Swap bytes for little-endian representation. - // As a result each pair of bytes will contain all bits of a single I or Q sample. - const __m256i shuffle_mask_0_epi8 = - _mm256_setr_epi64x(0x0304020301020001, 0x0708060705060405, 0x0405030402030102, 0x0809070806070506); - const __m256i shuffle_mask_1_epi8 = - _mm256_setr_epi64x(0x0506040503040203, 0x090a080907080607, 0xffffffffffffffff, 0xffffffffffffffff); - __m256i packed_data_0_le_epi8 = _mm256_shuffle_epi8(packed_data_0_epi8, shuffle_mask_0_epi8); - __m256i packed_data_1_le_epi8 = _mm256_shuffle_epi8(packed_data_1_epi8, shuffle_mask_1_epi8); - - // Do logical shift left, then arithmetical shift right in order to sign extend values. - // Note, AVX2 only allows to shift 32bit words using vector of indexes, so we do it twice. - const __m256i shl_0_epi32 = _mm256_setr_epi32(0, 2, 4, 6, 0, 2, 4, 6); - const __m256i shl_1_epi32 = _mm256_setr_epi32(1, 3, 5, 7, 1, 3, 5, 7); - // Mask 16bit words to use only shifted bits. - const __m256i mask_even_epi16 = _mm256_set1_epi32(0x0000ffff); - const __m256i mask_odd_epi16 = _mm256_set1_epi32(0xffff0000); - - __m256i unpacked_data_00_epi16 = _mm256_sllv_epi32(packed_data_0_le_epi8, shl_0_epi32); - __m256i unpacked_data_01_epi16 = _mm256_sllv_epi32(packed_data_0_le_epi8, shl_1_epi32); - __m256i unpacked_data_10_epi16 = _mm256_sllv_epi32(packed_data_1_le_epi8, shl_0_epi32); - __m256i unpacked_data_11_epi16 = _mm256_sllv_epi32(packed_data_1_le_epi8, shl_1_epi32); - unpacked_data_00_epi16 = _mm256_and_si256(unpacked_data_00_epi16, mask_even_epi16); - unpacked_data_01_epi16 = _mm256_and_si256(unpacked_data_01_epi16, mask_odd_epi16); - unpacked_data_10_epi16 = _mm256_and_si256(unpacked_data_10_epi16, mask_even_epi16); - unpacked_data_11_epi16 = _mm256_and_si256(unpacked_data_11_epi16, mask_odd_epi16); - - // Merge two vectors to get vector of shifted 16bit IQ samples, right-shift it to sign-extend values. - __m256i unpacked_data_0_epi16 = _mm256_srai_epi16(_mm256_or_si256(unpacked_data_00_epi16, unpacked_data_01_epi16), 7); - __m256i unpacked_data_1_epi16 = _mm256_srai_epi16(_mm256_or_si256(unpacked_data_10_epi16, unpacked_data_11_epi16), 7); - - // Write results. - _mm256_storeu_si256(reinterpret_cast<__m256i*>(unpacked_iq_data.data()), unpacked_data_0_epi16); - _mm256_storeu_si256(reinterpret_cast<__m256i*>(unpacked_iq_data.subspan(16, 8).data()), unpacked_data_1_epi16); -} - -void mm256::unpack_prb_big_endian(span unpacked_iq_data, span packed_data, unsigned iq_width) -{ - switch (iq_width) { - case 9: - unpack_prb_9b_be(unpacked_iq_data, packed_data); - break; - default: - report_fatal_error("Unsupported bit width"); - } -} diff --git a/lib/ofh/compression/packing_utils_avx2.h b/lib/ofh/compression/packing_utils_avx2.h index 79b1c49472..8adec8bce4 100644 --- a/lib/ofh/compression/packing_utils_avx2.h +++ b/lib/ofh/compression/packing_utils_avx2.h @@ -10,13 +10,146 @@ #pragma once +#include "srsran/adt/span.h" #include "srsran/ofh/compression/compressed_prb.h" +#include "srsran/support/error_handling.h" #include namespace srsran { namespace ofh { namespace mm256 { +/// \brief Packs 16bit IQ samples in one AVX2 register using 9bit big-endian format. +/// +/// \param[in] cmp_data_epi16 AVX2 register storing 16bit IQ samples. +/// \return An AVX2 register containing 18 packed bytes. +/// +/// \note Each 128bit lane of the input contains eight I and Q values, with each value consisting of 9 bits of data (the +/// LSB ones) and 7 bits of padding. The function packs the eight IQ samples (only the data bits, discarding the +/// padding) into the first 9 bytes of the respective 128bit lane of the output register (the remaining 7 bytes are +/// padding). Thus, the return value contains 18 packed data bytes in total. +inline __m256i pack_avx2_register_9b_be(__m256i cmp_data_epi16) +{ + // Input IQ samples need to be shifted in order to align bits before final packing. + // 0: i0 0 0 0 0 0 0 0 i8 i7 i6 i5 i4 i3 i2 i1 <- rotate right by 1 (shift left by 7, swap bytes later) + // 1: 0 q8 q7 q6 q5 q4 q3 q2 q1 q0 0 0 0 0 0 0 <- shift left by 6 + // 2: 0 0 i8 i7 i6 i5 i4 i3 i2 i1 i0 0 0 0 0 0 <- shift left by 5 + // 3: 0 0 0 q8 q7 q6 q5 q4 q3 q2 q1 q0 0 0 0 0 <- shift left by 4 + // 4: 0 0 0 0 i8 i7 i6 i5 i4 i3 i2 i1 i0 0 0 0 <- shift left by 3 + // 5: 0 0 0 0 0 q8 q7 q6 q5 q4 q3 q2 q1 q0 0 0 <- shift left by 2 + // 6: 0 0 0 0 0 0 i8 i7 i6 i5 i4 i3 i2 i1 i0 0 <- shift left by 1 + // 7: 0 0 0 0 0 0 0 q8 q7 q6 q5 q4 q3 q2 q1 q0 <- no shift + // ... the same pattern ... + // + // Note, AVX2 only allows shifting 32bit words using vector of indexes, so we do it twice. + const __m256i shift_0_epi32 = _mm256_setr_epi32(7, 5, 3, 1, 7, 5, 3, 1); + const __m256i shift_1_epi32 = _mm256_setr_epi32(6, 4, 2, 0, 6, 4, 2, 0); + __m256i cmp_data_sh0_epi16 = _mm256_sllv_epi32(cmp_data_epi16, shift_0_epi32); + __m256i cmp_data_sh1_epi16 = _mm256_sllv_epi32(cmp_data_epi16, shift_1_epi32); + // Mask 16bit words to keep only 9 shifted bits. + const __m256i mask_even_epi16 = + _mm256_setr_epi32(0x0000ff80, 0x00003fe0, 0x00000ff8, 0x000003fe, 0x0000ff80, 0x00003fe0, 0x00000ff8, 0x000003fe); + const __m256i mask_odd_epi16 = + _mm256_setr_epi32(0x7fc00000, 0x1ff00000, 0x07fc0000, 0x01ff0000, 0x7fc00000, 0x1ff00000, 0x07fc0000, 0x01ff0000); + cmp_data_sh0_epi16 = _mm256_and_si256(cmp_data_sh0_epi16, mask_even_epi16); + cmp_data_sh1_epi16 = _mm256_and_si256(cmp_data_sh1_epi16, mask_odd_epi16); + + // Merge two vectors to get vector of shifted IQ samples as explained above. + __m256i cmp_data_shifted_epi16 = _mm256_or_si256(cmp_data_sh0_epi16, cmp_data_sh1_epi16); + + // Shuffle it and create two new vectors that can be OR'ed to produce the final result. + __m256i cmp_data_v0_epi16 = _mm256_shuffle_epi8( + cmp_data_shifted_epi16, + _mm256_setr_epi64x(0x0c0a0806040200ff, 0xffffffffffffff0e, 0x0c0a0806040200ff, 0xffffffffffffff0e)); + __m256i cmp_data_v1_epi16 = _mm256_shuffle_epi8( + cmp_data_shifted_epi16, + _mm256_setr_epi64x(0x0f0d0b0907050301, 0xffffffffffffffff, 0x0f0d0b0907050301, 0xffffffffffffffff)); + // Perform 'bitwise OR' and return the result. + return _mm256_or_si256(cmp_data_v0_epi16, cmp_data_v1_epi16); +} + +/// \brief Packs 16bit IQ values of the two input RBs using 9bit big-endian format. +/// +/// The following diagram shows the input format. Here RBx stands for one unique RE (pair of IQ samples, 32 bits long) +/// pertaining to a respective RB): +/// | | | | | | +/// | ----- | ------- | ------- | ------- | ------- | +/// | \c r0: | RB0 RB0 | RB0 RB0 | RB0 RB0 | RB0 RB0 | +/// | \c r1: | RB0 RB0 | RB0 RB0 | RB1 RB1 | RB1 RB1 | +/// | \c r2: | RB1 RB1 | RB1 RB1 | RB1 RB1 | RB1 RB1 | +/// +/// \param[out] c_prbs Span of two compressed PRBs. +/// \param[in] r0 AVX2 register storing 16bit IQ samples of the first RB. +/// \param[in] r1 AVX2 register storing 16bit IQ samples of the first and second RB. +/// \param[in] r2 AVX2 register storing 16bit IQ samples of the second RB. +inline void avx2_pack_prbs_9b_big_endian(span c_prbs, __m256i r0, __m256i r1, __m256i r2) +{ + /// Number of bytes used by 1 packed resource block with IQ samples compressed to 9 bits. + static constexpr unsigned BYTES_PER_PRB_9BIT_COMPRESSION = 27; + + srsran_assert(c_prbs.size() == 2, "Output span must contain 2 resource blocks"); + + // Returns first 18 packed bytes out of 27 for the first RB (9 bytes in each 128bit lane - same applies below). + __m256i reg0_packed_epi8 = pack_avx2_register_9b_be(r0); + // Returns last 9 packed bytes out of 27 for the first RB and first 9 packed bytes for the second RB. + __m256i reg1_packed_epi8 = pack_avx2_register_9b_be(r1); + // Returns last 18 packed bytes out of 27 for the second RB. + __m256i reg2_packed_epi8 = pack_avx2_register_9b_be(r2); + + // AVX2 doesn't provide instruction to store specific bytes of the lanes using a mask, so we create new vectors, + // and use a regular store intrinsic. + // + // Next example explains the bytes permutations performed below for each RB to group its packed IQs. + // r0: {0xe959c2834776bd64, 0x8b, 0xdc0c7ca5b0ab3a56, 0x31} + // r1: {0xb1e93964f248fe46, 0xaf, 0x4f0f368e76fc7a9e, 0x12} + // r0_tmp0: {0xe959c2834776bd64, 0x000000000000008b, 0x0c7ca5b0ab3a5600, 0x00000000000031dc} + // r1_tmp0: {0x3964f248fe460000, 0x0000000000afb1e9, 0x0000000000000000, 0x0000000000000000} + // r0_tmp1: {0xe959c2834776bd64, 0x0c7ca5b0ab3a5600, 0x00000000000031dc, 0x0000000000000000} + // r1_tmp1: {0x0000000000000000, 0x0000000000000000, 0x3964f248fe460000, 0x0000000000afb1e9} + // rb0_tmp0: {0xe959c2834776bd64, 0x0c7ca5b0ab3a568b, XXXXXXXXXXXXXXXXXX, XXXXXXXXXXXXXXXXXX} + // rb0_tmp1: {XXXXXXXXXXXXXXXXXX, XXXXXXXXXXXXXXXXXX, 0x3964f248fe4631dc, 0x0000000000afb1e9} + // select 64bit words between rb0_tmp0 and rb0_tmp1: + // rb0: {0xe959c2834776bd64, 0x0c7ca5b0ab3a568b, 0x3964f248fe4631dc, 0x0000000000afb1e9} + + // Pack the first input RB. + const __m256i shuffle_mask_0 = + _mm256_setr_epi64x(0x0706050403020100, 0x0f0e0d0c0b0a0908, 0x06050403020100ff, 0xffffffffffff0807); + __m256i reg0_tmp0_epi8 = _mm256_shuffle_epi8(reg0_packed_epi8, shuffle_mask_0); + + const __m256i shuffle_mask_1 = + _mm256_setr_epi64x(0x050403020100ffff, 0xffffffffff080706, 0xffffffffffffffff, 0xffffffffffffffff); + __m256i reg1_tmp0_epi8 = _mm256_shuffle_epi8(reg1_packed_epi8, shuffle_mask_1); + + __m256i reg0_tmp1_epi8 = _mm256_permutevar8x32_epi32(reg0_tmp0_epi8, _mm256_setr_epi32(0, 1, 4, 5, 6, 7, 3, 3)); + __m256i reg1_tmp1_epi8 = _mm256_permute4x64_epi64(reg1_tmp0_epi8, 0b01001110); + + const __m256i sel_mask_0_epi8 = + _mm256_setr_epi64x(0x0000000000000000, 0x0000000000000000, 0xffffffffffffffff, 0xffffffffffffffff); + __m256i prb0_tmp0_epi8 = _mm256_or_si256(reg0_tmp0_epi8, reg0_tmp1_epi8); + __m256i prb0_tmp1_epi8 = _mm256_or_si256(reg0_tmp1_epi8, reg1_tmp1_epi8); + __m256i prb0_epi8 = _mm256_blendv_epi8(prb0_tmp0_epi8, prb0_tmp1_epi8, sel_mask_0_epi8); + + // Pack the second input RB. + const __m256i shuffle_mask_2 = + _mm256_setr_epi64x(0xffffffffffff0807, 0x06050403020100ff, 0x050403020100ffff, 0xffffffffff080706); + __m256i reg1_tmp2_epi8 = _mm256_permutevar8x32_epi32(reg1_packed_epi8, _mm256_setr_epi32(4, 5, 6, 7, 3, 3, 3, 3)); + __m256i reg2_tmp0_epi8 = _mm256_shuffle_epi8(reg2_packed_epi8, shuffle_mask_2); + __m256i reg2_tmp1_epi8 = _mm256_permutevar8x32_epi32(reg2_tmp0_epi8, _mm256_setr_epi32(1, 1, 2, 3, 0, 1, 6, 7)); + + const __m256i sel_mask_1_epi8 = + _mm256_setr_epi64x(0x0000000000000000, 0x0000000000000000, 0xffffffffffffffff, 0xffffffffffffffff); + __m256i prb1_tmp0_epi8 = _mm256_or_si256(reg1_tmp2_epi8, reg2_tmp1_epi8); + __m256i prb1_tmp1_epi8 = _mm256_or_si256(reg2_tmp0_epi8, reg2_tmp1_epi8); + __m256i prb1_epi8 = _mm256_blendv_epi8(prb1_tmp0_epi8, prb1_tmp1_epi8, sel_mask_1_epi8); + + // Write resource blocks to the memory. + _mm256_storeu_si256(reinterpret_cast<__m256i*>(c_prbs[0].get_byte_buffer().data()), prb0_epi8); + c_prbs[0].set_stored_size(BYTES_PER_PRB_9BIT_COMPRESSION); + + _mm256_storeu_si256(reinterpret_cast<__m256i*>(c_prbs[1].get_byte_buffer().data()), prb1_epi8); + c_prbs[1].set_stored_size(BYTES_PER_PRB_9BIT_COMPRESSION); +} + /// \brief Packs 16bit IQ values of the two RBs using the specified width and big-endian format. /// /// The following diagram shows the input format. Here RBx stands for one unique RE (pair of IQ samples, 32 bits long) @@ -32,7 +165,72 @@ namespace mm256 { /// \param[in] r1 AVX2 register storing 16bit IQ pairs of the first and second PRB. /// \param[in] r2 AVX2 register storing 16bit IQ pairs of the second PRB. /// \param[in] iq_width Bit width of the resulting packed IQ samples. -void pack_prbs_big_endian(span c_prbs, __m256i r0, __m256i r1, __m256i r2, unsigned iq_width); +inline void +pack_prbs_big_endian(span c_prbs, __m256i r0, __m256i r1, __m256i r2, unsigned iq_width) +{ + switch (iq_width) { + case 9: + avx2_pack_prbs_9b_big_endian(c_prbs, r0, r1, r2); + break; + default: + report_fatal_error("Unsupported bit width"); + } +} + +/// \brief Unpacks packed 9bit IQ samples stored as bytes in big-endian format to an array of 16bit signed values. +/// +/// \param[out] unpacked_iq_data A span of 16bit integers, corresponding to \c NOF_CARRIERS_PER_RB unpacked IQ pairs. +/// \param[in] packed_data A span of 27 packed bytes. +/// +/// \note The \c unpacked_iq_data parameter should be sized to store 32 output IQ samples: it is 24 IQ samples of one RB +/// rounded up to 32-byte boundary required by AVX2 intrinsics. +inline void unpack_prb_9b_be(span unpacked_iq_data, span packed_data) +{ + constexpr size_t avx2_size_short_words = 16; + srsran_assert(unpacked_iq_data.size() >= avx2_size_short_words * 2, "Wrong unpacked data span size"); + + // Load input, 27 bytes (fits in one AVX2 register). + __m256i packed_data_epi8 = _mm256_loadu_si256(reinterpret_cast(packed_data.data())); + + // Duplicate input words (it is required since below in the code every byte will be used twice: + // to provide MSB bits of the current IQ sample and LSB bits of the previous IQ sample). + __m256i packed_data_0_epi8 = _mm256_permute4x64_epi64(packed_data_epi8, 0b10010100); + __m256i packed_data_1_epi8 = _mm256_permute4x64_epi64(packed_data_epi8, 0b00001110); + + // Swap bytes for little-endian representation. + // As a result each pair of bytes will contain all bits of a single I or Q sample. + const __m256i shuffle_mask_0_epi8 = + _mm256_setr_epi64x(0x0304020301020001, 0x0708060705060405, 0x0405030402030102, 0x0809070806070506); + const __m256i shuffle_mask_1_epi8 = + _mm256_setr_epi64x(0x0506040503040203, 0x090a080907080607, 0xffffffffffffffff, 0xffffffffffffffff); + __m256i packed_data_0_le_epi8 = _mm256_shuffle_epi8(packed_data_0_epi8, shuffle_mask_0_epi8); + __m256i packed_data_1_le_epi8 = _mm256_shuffle_epi8(packed_data_1_epi8, shuffle_mask_1_epi8); + + // Do logical shift left, then arithmetical shift right in order to sign extend values. + // Note, AVX2 only allows to shift 32bit words using vector of indexes, so we do it twice. + const __m256i shl_0_epi32 = _mm256_setr_epi32(0, 2, 4, 6, 0, 2, 4, 6); + const __m256i shl_1_epi32 = _mm256_setr_epi32(1, 3, 5, 7, 1, 3, 5, 7); + // Mask 16bit words to use only shifted bits. + const __m256i mask_even_epi16 = _mm256_set1_epi32(0x0000ffff); + const __m256i mask_odd_epi16 = _mm256_set1_epi32(0xffff0000); + + __m256i unpacked_data_00_epi16 = _mm256_sllv_epi32(packed_data_0_le_epi8, shl_0_epi32); + __m256i unpacked_data_01_epi16 = _mm256_sllv_epi32(packed_data_0_le_epi8, shl_1_epi32); + __m256i unpacked_data_10_epi16 = _mm256_sllv_epi32(packed_data_1_le_epi8, shl_0_epi32); + __m256i unpacked_data_11_epi16 = _mm256_sllv_epi32(packed_data_1_le_epi8, shl_1_epi32); + unpacked_data_00_epi16 = _mm256_and_si256(unpacked_data_00_epi16, mask_even_epi16); + unpacked_data_01_epi16 = _mm256_and_si256(unpacked_data_01_epi16, mask_odd_epi16); + unpacked_data_10_epi16 = _mm256_and_si256(unpacked_data_10_epi16, mask_even_epi16); + unpacked_data_11_epi16 = _mm256_and_si256(unpacked_data_11_epi16, mask_odd_epi16); + + // Merge two vectors to get vector of shifted 16bit IQ samples, right-shift it to sign-extend values. + __m256i unpacked_data_0_epi16 = _mm256_srai_epi16(_mm256_or_si256(unpacked_data_00_epi16, unpacked_data_01_epi16), 7); + __m256i unpacked_data_1_epi16 = _mm256_srai_epi16(_mm256_or_si256(unpacked_data_10_epi16, unpacked_data_11_epi16), 7); + + // Write results. + _mm256_storeu_si256(reinterpret_cast<__m256i*>(unpacked_iq_data.data()), unpacked_data_0_epi16); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(unpacked_iq_data.subspan(16, 8).data()), unpacked_data_1_epi16); +} /// \brief Unpacks packed IQ samples stored as bytes in big-endian format to an array of 16bit signed values. /// @@ -42,13 +240,25 @@ void pack_prbs_big_endian(span c_prbs, __m256i r0, __m256i /// /// \note The \c unpacked_iq_data parameter should be sized to store 32 output IQ samples: it is 24 IQ samples of one RB /// rounded up to 32-byte boundary required by AVX2 intrinsics. -void unpack_prb_big_endian(span unpacked_iq_data, span packed_data, unsigned iq_width); +void unpack_prb_big_endian(span unpacked_iq_data, span packed_data, unsigned iq_width) +{ + switch (iq_width) { + case 9: + unpack_prb_9b_be(unpacked_iq_data, packed_data); + break; + default: + report_fatal_error("Unsupported bit width"); + } +} /// \brief Checks whether the requested bit width is supported by the AVX2 implementation. /// \param[in] iq_width Requested bit width. /// /// \return True in case packing/unpacking with the requested bit width is supported -bool iq_width_packing_supported(unsigned iq_width); +inline bool iq_width_packing_supported(unsigned iq_width) +{ + return iq_width == 9; +} } // namespace mm256 } // namespace ofh diff --git a/lib/ofh/compression/packing_utils_avx512.cpp b/lib/ofh/compression/packing_utils_avx512.cpp deleted file mode 100644 index bb150f3b68..0000000000 --- a/lib/ofh/compression/packing_utils_avx512.cpp +++ /dev/null @@ -1,207 +0,0 @@ -/* - * - * Copyright 2021-2024 Software Radio Systems Limited - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the distribution. - * - */ - -#include "packing_utils_avx512.h" -#include "srsran/support/error_handling.h" - -using namespace srsran; -using namespace ofh; - -/// Number of bytes used by 1 packed PRB with IQ samples compressed to 9 bits. -static constexpr unsigned BYTES_PER_PRB_9BIT_COMPRESSION = 27; - -/// Number of bytes used by 1 packed PRB with non-compressed 16 bits IQ samples. -static constexpr unsigned BYTES_PER_PRB_NO_COMPRESSION = 48; - -bool mm512::iq_width_packing_supported(unsigned iq_width) -{ - if ((iq_width == 9) || (iq_width == 16)) { - return true; - } - return false; -} - -/// \brief Packs 16bit IQ values of the PRB using given bit width and big-endian format. -/// -/// \param[out] c_prb Compressed PRB object storing packed bytes. -/// \param[in] reg AVX512 register storing 16bit IQ samples of the PRB. -static void avx512_pack_prb_9b_big_endian(compressed_prb& c_prb, __m512i reg) -{ - static constexpr unsigned bytes_per_lane = BYTES_PER_PRB_9BIT_COMPRESSION / 3; - static constexpr unsigned lane_write_mask = 0x01ff; - - // Input IQ samples need to be shifted in order to align bits before final packing. - // 0: i0 0 0 0 0 0 0 0 i8 i7 i6 i5 i4 i3 i2 i1 <- rotate right by 1 (shift left by 7, swap bytes later) - // 1: 0 q8 q7 q6 q5 q4 q3 q2 q1 q0 0 0 0 0 0 0 <- shift left by 6 - // 2: 0 0 i8 i7 i6 i5 i4 i3 i2 i1 i0 0 0 0 0 0 <- shift left by 5 - // 3: 0 0 0 q8 q7 q6 q5 q4 q3 q2 q1 q0 0 0 0 0 <- shift left by 4 - // 4: 0 0 0 0 i8 i7 i6 i5 i4 i3 i2 i1 i0 0 0 0 <- shift left by 3 - // 5: 0 0 0 0 0 q8 q7 q6 q5 q4 q3 q2 q1 q0 0 0 <- shift left by 2 - // 6: 0 0 0 0 0 0 i8 i7 i6 i5 i4 i3 i2 i1 i0 0 <- shift left by 1 - // 7: 0 0 0 0 0 0 0 q8 q7 q6 q5 q4 q3 q2 q1 q0 <- no shift - // ... the same pattern in every 128bit lane ... - - const __m512i shiftv_epi16 = - _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7); - __m512i iq_shl_epi16 = _mm512_sllv_epi16(reg, shiftv_epi16); - - // Mask 16bit words to keep only 9 shifted bits. - const __m512i mask_epi16 = _mm512_set_epi64(0x01ff03fe07fc0ff8, - 0x1ff03fe07fc0ff80, - 0x01ff03fe07fc0ff8, - 0x1ff03fe07fc0ff80, - 0x01ff03fe07fc0ff8, - 0x1ff03fe07fc0ff80, - 0x01ff03fe07fc0ff8, - 0x1ff03fe07fc0ff80); - iq_shl_epi16 = _mm512_and_si512(iq_shl_epi16, mask_epi16); - - // Shuffle it and create two new vectors that can be OR'ed to produce final result. Temporal vectors look as follows: - // 0 0 0 0 0 0 0 0 | i0 0 0 0 0 0 0 0 | q1 q0 0 0 0 0 0 0 | i2 i1 i0 0 0 0 0 0 | ... - // i8 i7 i6 i5 i4 i3 i2 i1 | 0 q8 q7 q6 q5 q4 q3 q2 | 0 0 i8 i7 i6 i5 i4 i3 | 0 0 0 q8 q7 q6 q5 q4 | ... - __m512i tmp_iq_0_epi8 = _mm512_shuffle_epi8(iq_shl_epi16, - _mm512_setr_epi64(0x0c0a0806040200ff, - 0xffffffffffffff0e, - 0x0c0a0806040200ff, - 0xffffffffffffff0e, - 0x0c0a0806040200ff, - 0xffffffffffffff0e, - 0xffffffffffffffff, - 0xffffffffffffffff)); - __m512i tmp_iq_1_epi8 = _mm512_shuffle_epi8(iq_shl_epi16, - _mm512_setr_epi64(0x0f0d0b0907050301, - 0xffffffffffffffff, - 0x0f0d0b0907050301, - 0xffffffffffffffff, - 0x0f0d0b0907050301, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff)); - - // Perform 'bitwise OR'. - __m512i iq_packed_epi8 = _mm512_or_si512(tmp_iq_0_epi8, tmp_iq_1_epi8); - - // Store first 9 bytes of the first three 128bit lanes of the AVX512 register. - uint8_t* data = c_prb.get_byte_buffer().data(); - _mm_mask_storeu_epi8(data, lane_write_mask, _mm512_extracti64x2_epi64(iq_packed_epi8, 0)); - _mm_mask_storeu_epi8(data + bytes_per_lane, lane_write_mask, _mm512_extracti64x2_epi64(iq_packed_epi8, 1)); - _mm_mask_storeu_epi8(data + bytes_per_lane * 2, lane_write_mask, _mm512_extracti64x2_epi64(iq_packed_epi8, 2)); - - c_prb.set_stored_size(BYTES_PER_PRB_9BIT_COMPRESSION); -} - -/// \brief Packs 16bit IQ values of the PRB using given bit width and big-endian format. -/// -/// \param[out] c_prb Compressed PRB object storing packed bytes. -/// \param[in] reg AVX512 register storing 16bit IQ samples of the PRB. -static void avx512_pack_prb_16b_big_endian(compressed_prb& c_prb, __m512i reg) -{ - static constexpr unsigned write_mask = 0xffffff; - - // Input contains 24 16 bit Iand Q samples. - uint8_t* data = c_prb.get_byte_buffer().data(); - - // Swap bytes to convert from big-endian format and write them directly to the output memory. - const __m512i shuffle_mask_epi8 = _mm512_setr_epi64(0x0607040502030001, - 0x0e0f0c0d0a0b0809, - 0x1617141512131011, - 0x1e1f1c1d1a1b1819, - 0x2627242522232021, - 0x2e2f2c2d2a2b2829, - 0x3637343532333031, - 0x3e3f3c3d3a3b3839); - - __m512i reg_swp_epi16 = _mm512_shuffle_epi8(reg, shuffle_mask_epi8); - _mm512_mask_storeu_epi16(data, write_mask, reg_swp_epi16); - c_prb.set_stored_size(BYTES_PER_PRB_NO_COMPRESSION); -} - -void mm512::pack_prb_big_endian(compressed_prb& c_prb, __m512i reg, unsigned iq_width) -{ - if (iq_width == 9) { - return avx512_pack_prb_9b_big_endian(c_prb, reg); - } - if (iq_width == 16) { - return avx512_pack_prb_16b_big_endian(c_prb, reg); - } - report_fatal_error("Unsupported bit width"); -} - -/// \brief Unpacks packed 9bit IQ samples stored as bytes in big-endian format to an array of 16bit signed values. -/// -/// \param[out] unpacked_iq_data A span of 16bit integers, corresponding to \c NOF_CARRIERS_PER_RB unpacked IQ pairs. -/// \param[in] packed_data A span of 27 packed bytes. -/// -/// \note The \c unpacked_iq_data parameter should be sized to store 32 output IQ samples: it is 24 IQ samples of one RB -/// rounded up to 64-byte boundary required by AVX512 intrinsics. -static void avx512_unpack_prb_9b_be(span unpacked_iq_data, span packed_data) -{ - // Load input, 27 bytes (fits in one AVX512 register). - __m512i packed_data_epi8 = _mm512_mask_loadu_epi8(_mm512_set1_epi64(0), 0x1fffffff, packed_data.data()); - - // Duplicate input words (it is required since below in the code every byte will be used twice: - // to provide MSB bits of the current IQ sample and LSB bits of the previous IQ sample). - __m512i packed_data_0_epi8 = _mm512_mask_permutexvar_epi64( - _mm512_set1_epi64(0), 0xff, _mm512_setr_epi64(0, 1, 1, 2, 2, 3, 0, 0), packed_data_epi8); - - // Swap bytes for little-endian representation. Each pair of bytes contains all bits of a single I or Q sample. - const __m512i shuffle_mask_epi8 = _mm512_setr_epi64(0x0304020301020001, - 0x0708060705060405, - 0x0405030402030102, - 0x0809070806070506, - 0x0506040503040203, - 0x090a080907080607, - 0xffffffffffffffff, - 0xffffffffffffffff); - - __m512i packed_data_0_le_epi16 = _mm512_shuffle_epi8(packed_data_0_epi8, shuffle_mask_epi8); - - // Shift left to align to 16bit boundary, then shift right to sign-extend values. - const __m512i shl_mask_epi16 = - _mm512_set_epi16(7, 6, 5, 4, 3, 2, 1, 0, 7, 6, 5, 4, 3, 2, 1, 0, 7, 6, 5, 4, 3, 2, 1, 0, 7, 6, 5, 4, 3, 2, 1, 0); - __m512i unpacked_data_epi16 = _mm512_srai_epi16(_mm512_sllv_epi16(packed_data_0_le_epi16, shl_mask_epi16), 7); - - // Write results to the output buffer. - _mm512_mask_storeu_epi16(unpacked_iq_data.data(), 0x00ffffff, unpacked_data_epi16); -} - -/// \brief Unpacks packed 16bit IQ samples stored as bytes in big-endian format to an array of 16bit signed values. -/// -/// \param[out] unpacked_iq_data A span of 16bit integers, corresponding to \c NOF_CARRIERS_PER_RB unpacked IQ pairs. -/// \param[in] packed_data A span of 48 packed bytes. -static void avx512_unpack_prb_16b_be(span unpacked_iq_data, span packed_data) -{ - // Load input, 48 bytes (fits in one AVX512 register). - const __mmask32 rw_mask = 0x00ffffff; - __m512i packed_data_epi16 = _mm512_maskz_loadu_epi16(rw_mask, packed_data.data()); - // Swap bytes for Little-endian representation. - const __m512i shuffle_mask_epi8 = _mm512_setr_epi64(0x0607040502030001, - 0x0e0f0c0d0a0b0809, - 0x1617141512131011, - 0x1e1f1c1d1a1b1819, - 0x2627242522232021, - 0x2e2f2c2d2a2b2829, - 0x3637343532333031, - 0x3e3f3c3d3a3b3839); - - __m512i unpacked_data_epi16 = _mm512_shuffle_epi8(packed_data_epi16, shuffle_mask_epi8); - _mm512_mask_storeu_epi16(unpacked_iq_data.data(), rw_mask, unpacked_data_epi16); -} - -void mm512::unpack_prb_big_endian(span unpacked_iq_data, span packed_data, unsigned iq_width) -{ - if (iq_width == 9) { - return avx512_unpack_prb_9b_be(unpacked_iq_data, packed_data); - } - if (iq_width == 16) { - return avx512_unpack_prb_16b_be(unpacked_iq_data, packed_data); - } - report_fatal_error("Unsupported bit width"); -} diff --git a/lib/ofh/compression/packing_utils_avx512.h b/lib/ofh/compression/packing_utils_avx512.h index 7e72b8d533..73479b1137 100644 --- a/lib/ofh/compression/packing_utils_avx512.h +++ b/lib/ofh/compression/packing_utils_avx512.h @@ -12,17 +12,185 @@ #include "avx512_helpers.h" #include "srsran/ofh/compression/compressed_prb.h" +#include "srsran/support/error_handling.h" namespace srsran { namespace ofh { namespace mm512 { +/// \brief Packs 16bit IQ values of the PRB as 9 bit values in big-endian format. +/// +/// \param[out] c_prb Compressed PRB object storing packed bytes. +/// \param[in] reg AVX512 register storing 16bit IQ samples of the PRB. +inline void avx512_pack_prb_9b_big_endian(compressed_prb& c_prb, __m512i reg) +{ + static constexpr unsigned BYTES_PER_PRB_9BIT_COMPRESSION = 27; + static constexpr unsigned bytes_per_lane = BYTES_PER_PRB_9BIT_COMPRESSION / 3; + static constexpr unsigned lane_write_mask = 0x01ff; + + // Input IQ samples need to be shifted in order to align bits before final packing. + // 0: i0 0 0 0 0 0 0 0 i8 i7 i6 i5 i4 i3 i2 i1 <- rotate right by 1 (shift left by 7, swap bytes later) + // 1: 0 q8 q7 q6 q5 q4 q3 q2 q1 q0 0 0 0 0 0 0 <- shift left by 6 + // 2: 0 0 i8 i7 i6 i5 i4 i3 i2 i1 i0 0 0 0 0 0 <- shift left by 5 + // 3: 0 0 0 q8 q7 q6 q5 q4 q3 q2 q1 q0 0 0 0 0 <- shift left by 4 + // 4: 0 0 0 0 i8 i7 i6 i5 i4 i3 i2 i1 i0 0 0 0 <- shift left by 3 + // 5: 0 0 0 0 0 q8 q7 q6 q5 q4 q3 q2 q1 q0 0 0 <- shift left by 2 + // 6: 0 0 0 0 0 0 i8 i7 i6 i5 i4 i3 i2 i1 i0 0 <- shift left by 1 + // 7: 0 0 0 0 0 0 0 q8 q7 q6 q5 q4 q3 q2 q1 q0 <- no shift + // ... the same pattern in every 128bit lane ... + + const __m512i shiftv_epi16 = + _mm512_set_epi16(0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7); + __m512i iq_shl_epi16 = _mm512_sllv_epi16(reg, shiftv_epi16); + + // Mask 16bit words to keep only 9 shifted bits. + const __m512i mask_epi16 = _mm512_set_epi64(0x01ff03fe07fc0ff8, + 0x1ff03fe07fc0ff80, + 0x01ff03fe07fc0ff8, + 0x1ff03fe07fc0ff80, + 0x01ff03fe07fc0ff8, + 0x1ff03fe07fc0ff80, + 0x01ff03fe07fc0ff8, + 0x1ff03fe07fc0ff80); + iq_shl_epi16 = _mm512_and_si512(iq_shl_epi16, mask_epi16); + + // Shuffle it and create two new vectors that can be OR'ed to produce final result. Temporal vectors look as follows: + // 0 0 0 0 0 0 0 0 | i0 0 0 0 0 0 0 0 | q1 q0 0 0 0 0 0 0 | i2 i1 i0 0 0 0 0 0 | ... + // i8 i7 i6 i5 i4 i3 i2 i1 | 0 q8 q7 q6 q5 q4 q3 q2 | 0 0 i8 i7 i6 i5 i4 i3 | 0 0 0 q8 q7 q6 q5 q4 | ... + __m512i tmp_iq_0_epi8 = _mm512_shuffle_epi8(iq_shl_epi16, + _mm512_setr_epi64(0x0c0a0806040200ff, + 0xffffffffffffff0e, + 0x0c0a0806040200ff, + 0xffffffffffffff0e, + 0x0c0a0806040200ff, + 0xffffffffffffff0e, + 0xffffffffffffffff, + 0xffffffffffffffff)); + __m512i tmp_iq_1_epi8 = _mm512_shuffle_epi8(iq_shl_epi16, + _mm512_setr_epi64(0x0f0d0b0907050301, + 0xffffffffffffffff, + 0x0f0d0b0907050301, + 0xffffffffffffffff, + 0x0f0d0b0907050301, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff)); + + // Perform 'bitwise OR'. + __m512i iq_packed_epi8 = _mm512_or_si512(tmp_iq_0_epi8, tmp_iq_1_epi8); + + // Store first 9 bytes of the first three 128bit lanes of the AVX512 register. + uint8_t* data = c_prb.get_byte_buffer().data(); + _mm_mask_storeu_epi8(data, lane_write_mask, _mm512_extracti64x2_epi64(iq_packed_epi8, 0)); + _mm_mask_storeu_epi8(data + bytes_per_lane, lane_write_mask, _mm512_extracti64x2_epi64(iq_packed_epi8, 1)); + _mm_mask_storeu_epi8(data + bytes_per_lane * 2, lane_write_mask, _mm512_extracti64x2_epi64(iq_packed_epi8, 2)); + + c_prb.set_stored_size(BYTES_PER_PRB_9BIT_COMPRESSION); +} + +/// \brief Packs 16bit IQ values of the PRB using big-endian format. +/// +/// \param[out] c_prb Compressed PRB object storing packed bytes. +/// \param[in] reg AVX512 register storing 16bit IQ samples of the PRB. +inline void avx512_pack_prb_16b_big_endian(compressed_prb& c_prb, __m512i reg) +{ + static constexpr unsigned BYTES_PER_PRB_NO_COMPRESSION = 48; + static constexpr unsigned write_mask = 0xffffff; + + // Input contains 24 16 bit Iand Q samples. + uint8_t* data = c_prb.get_byte_buffer().data(); + + // Swap bytes to convert from big-endian format and write them directly to the output memory. + const __m512i shuffle_mask_epi8 = _mm512_setr_epi64(0x0607040502030001, + 0x0e0f0c0d0a0b0809, + 0x1617141512131011, + 0x1e1f1c1d1a1b1819, + 0x2627242522232021, + 0x2e2f2c2d2a2b2829, + 0x3637343532333031, + 0x3e3f3c3d3a3b3839); + + __m512i reg_swp_epi16 = _mm512_shuffle_epi8(reg, shuffle_mask_epi8); + _mm512_mask_storeu_epi16(data, write_mask, reg_swp_epi16); + c_prb.set_stored_size(BYTES_PER_PRB_NO_COMPRESSION); +} + /// \brief Packs 16bit IQ values of a resource block using the specified width and big-endian format. /// /// \param[out] c_prb Output PRB storing compressed packed bytes. /// \param[in] reg AVX512 register storing 16bit IQ pairs of the PRB. /// \param[in] iq_width Bit width of the resulting packed IQ samples. -void pack_prb_big_endian(ofh::compressed_prb& c_prb, __m512i reg, unsigned iq_width); +inline void pack_prb_big_endian(ofh::compressed_prb& c_prb, __m512i reg, unsigned iq_width) +{ + if (iq_width == 9) { + return avx512_pack_prb_9b_big_endian(c_prb, reg); + } + if (iq_width == 16) { + return avx512_pack_prb_16b_big_endian(c_prb, reg); + } + report_fatal_error("Unsupported bit width"); +} + +/// \brief Unpacks packed 9bit IQ samples stored as bytes in big-endian format to an array of 16bit signed values. +/// +/// \param[out] unpacked_iq_data A span of 16bit integers, corresponding to \c NOF_CARRIERS_PER_RB unpacked IQ pairs. +/// \param[in] packed_data A span of 27 packed bytes. +/// +/// \note The \c unpacked_iq_data parameter should be sized to store 32 output IQ samples: it is 24 IQ samples of one RB +/// rounded up to 64-byte boundary required by AVX512 intrinsics. +inline void avx512_unpack_prb_9b_be(span unpacked_iq_data, span packed_data) +{ + // Load input, 27 bytes (fits in one AVX512 register). + __m512i packed_data_epi8 = _mm512_mask_loadu_epi8(_mm512_set1_epi64(0), 0x1fffffff, packed_data.data()); + + // Duplicate input words (it is required since below in the code every byte will be used twice: + // to provide MSB bits of the current IQ sample and LSB bits of the previous IQ sample). + __m512i packed_data_0_epi8 = _mm512_mask_permutexvar_epi64( + _mm512_set1_epi64(0), 0xff, _mm512_setr_epi64(0, 1, 1, 2, 2, 3, 0, 0), packed_data_epi8); + + // Swap bytes for little-endian representation. Each pair of bytes contains all bits of a single I or Q sample. + const __m512i shuffle_mask_epi8 = _mm512_setr_epi64(0x0304020301020001, + 0x0708060705060405, + 0x0405030402030102, + 0x0809070806070506, + 0x0506040503040203, + 0x090a080907080607, + 0xffffffffffffffff, + 0xffffffffffffffff); + + __m512i packed_data_0_le_epi16 = _mm512_shuffle_epi8(packed_data_0_epi8, shuffle_mask_epi8); + + // Shift left to align to 16bit boundary, then shift right to sign-extend values. + const __m512i shl_mask_epi16 = + _mm512_set_epi16(7, 6, 5, 4, 3, 2, 1, 0, 7, 6, 5, 4, 3, 2, 1, 0, 7, 6, 5, 4, 3, 2, 1, 0, 7, 6, 5, 4, 3, 2, 1, 0); + __m512i unpacked_data_epi16 = _mm512_srai_epi16(_mm512_sllv_epi16(packed_data_0_le_epi16, shl_mask_epi16), 7); + + // Write results to the output buffer. + _mm512_mask_storeu_epi16(unpacked_iq_data.data(), 0x00ffffff, unpacked_data_epi16); +} + +/// \brief Unpacks packed 16bit IQ samples stored as bytes in big-endian format to an array of 16bit signed values. +/// +/// \param[out] unpacked_iq_data A span of 16bit integers, corresponding to \c NOF_CARRIERS_PER_RB unpacked IQ pairs. +/// \param[in] packed_data A span of 48 packed bytes. +inline void avx512_unpack_prb_16b_be(span unpacked_iq_data, span packed_data) +{ + // Load input, 48 bytes (fits in one AVX512 register). + const __mmask32 rw_mask = 0x00ffffff; + __m512i packed_data_epi16 = _mm512_maskz_loadu_epi16(rw_mask, packed_data.data()); + // Swap bytes for Little-endian representation. + const __m512i shuffle_mask_epi8 = _mm512_setr_epi64(0x0607040502030001, + 0x0e0f0c0d0a0b0809, + 0x1617141512131011, + 0x1e1f1c1d1a1b1819, + 0x2627242522232021, + 0x2e2f2c2d2a2b2829, + 0x3637343532333031, + 0x3e3f3c3d3a3b3839); + + __m512i unpacked_data_epi16 = _mm512_shuffle_epi8(packed_data_epi16, shuffle_mask_epi8); + _mm512_mask_storeu_epi16(unpacked_iq_data.data(), rw_mask, unpacked_data_epi16); +} /// \brief Unpacks packed IQ samples stored as bytes in big-endian format to an array of 16bit signed values. /// @@ -32,13 +200,28 @@ void pack_prb_big_endian(ofh::compressed_prb& c_prb, __m512i reg, unsigned iq_wi /// /// \note The \c unpacked_iq_data parameter should be sized to store 32 output IQ samples: it is 24 IQ samples of one RB /// rounded up to 64-byte boundary required by AVX512 intrinsics. -void unpack_prb_big_endian(span unpacked_iq_data, span packed_data, unsigned iq_width); +inline void unpack_prb_big_endian(span unpacked_iq_data, span packed_data, unsigned iq_width) +{ + if (iq_width == 9) { + return avx512_unpack_prb_9b_be(unpacked_iq_data, packed_data); + } + if (iq_width == 16) { + return avx512_unpack_prb_16b_be(unpacked_iq_data, packed_data); + } + report_fatal_error("Unsupported bit width"); +} /// \brief Checks whether the requested bit width is supported by the AVX512 implementation. /// \param[in] iq_width Requested bit width. /// /// \return True in case packing/unpacking with the requested bit width is supported. -bool iq_width_packing_supported(unsigned iq_width); +inline bool iq_width_packing_supported(unsigned iq_width) +{ + if ((iq_width == 9) || (iq_width == 16)) { + return true; + } + return false; +} } // namespace mm512 } // namespace ofh diff --git a/lib/ofh/compression/packing_utils_neon.cpp b/lib/ofh/compression/packing_utils_neon.cpp deleted file mode 100644 index fb1d53ac8f..0000000000 --- a/lib/ofh/compression/packing_utils_neon.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* - * - * Copyright 2021-2024 Software Radio Systems Limited - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the distribution. - * - */ - -#include "packing_utils_neon.h" -#include "srsran/support/error_handling.h" - -using namespace srsran; -using namespace ofh; - -/// Number of bytes used by 1 packed PRB with IQ samples compressed to 9 bits. -static constexpr unsigned BYTES_PER_PRB_9BIT_COMPRESSION = 27; - -bool neon::iq_width_packing_supported(unsigned iq_width) -{ - return iq_width == 9; -} - -/// \brief Reads eight 16bit IQ values from input NEON register and packs them to the first 72 bits of the output NEON -/// register in big-endian format, thus occupying 9 output bytes. -/// -/// \param[in] regs NEON register storing 16bit IQ samples of a resource block. -/// \return NEON register storing 9 packed bytes. -static uint8x16_t pack_neon_register_9b_big_endian(int16x8_t reg) -{ - // Input IQ samples need to be shifted in order to align bits before final packing. - // 0: i0 0 0 0 0 0 0 0 i8 i7 i6 i5 i4 i3 i2 i1 <- rotate right by 1 (shift left by 7, swap bytes later) - // 1: 0 q8 q7 q6 q5 q4 q3 q2 q1 q0 0 0 0 0 0 0 <- shift left by 6 - // 2: 0 0 i8 i7 i6 i5 i4 i3 i2 i1 i0 0 0 0 0 0 <- shift left by 5 - // 3: 0 0 0 q8 q7 q6 q5 q4 q3 q2 q1 q0 0 0 0 0 <- shift left by 4 - // 4: 0 0 0 0 i8 i7 i6 i5 i4 i3 i2 i1 i0 0 0 0 <- shift left by 3 - // 5: 0 0 0 0 0 q8 q7 q6 q5 q4 q3 q2 q1 q0 0 0 <- shift left by 2 - // 6: 0 0 0 0 0 0 i8 i7 i6 i5 i4 i3 i2 i1 i0 0 <- shift left by 1 - // 7: 0 0 0 0 0 0 0 q8 q7 q6 q5 q4 q3 q2 q1 q0 <- no shift - - // Shift data according to the mask described above. - const int16x8_t shift_mask_s16 = vcombine_s16(vcreate_s16(0x0004000500060007), vcreate_s16(0x0000000100020003)); - int16x8_t iq_shl_s16 = vshlq_s16(reg, shift_mask_s16); - - // Mask 16bit words to keep only 9 shifted bits. - const int16x8_t mask_s16 = vcombine_s16(vcreate_s16(0x1ff03fe07fc0ff80), vcreate_s16(0x01ff03fe07fc0ff8)); - iq_shl_s16 = vandq_s16(iq_shl_s16, mask_s16); - - // Shuffle it and create two new vectors that can be OR'ed to produce final result. Temporal vectors look as follows: - // 0 0 0 0 0 0 0 0 | i0 0 0 0 0 0 0 0 | q1 q0 0 0 0 0 0 0 | i2 i1 i0 0 0 0 0 0 | ... - // i8 i7 i6 i5 i4 i3 i2 i1 | 0 q8 q7 q6 q5 q4 q3 q2 | 0 0 i8 i7 i6 i5 i4 i3 | 0 0 0 q8 q7 q6 q5 q4 | ... - int8x16_t iq_shl_s8 = vreinterpretq_s8_s16(iq_shl_s16); - int8x16_t tmp_iq_0_s8 = - vqtbl1q_s8(iq_shl_s8, vcombine_u8(vcreate_u8(0x0c0a0806040200ff), vcreate_u8(0xffffffffffffff0e))); - int8x16_t tmp_iq_1_s8 = - vqtbl1q_s8(iq_shl_s8, vcombine_u8(vcreate_u8(0x0f0d0b0907050301), vcreate_u8(0xffffffffffffffff))); - - // Perform 'bitwise OR'. - return vorrq_u8(vreinterpretq_u8_s8(tmp_iq_0_s8), vreinterpretq_u8_s8(tmp_iq_1_s8)); -} - -/// \brief Packs 16bit IQ values of the PRB using given bit width and big-endian format. -/// -/// \param[out] c_prb Compressed PRB object storing packed bytes. -/// \param[in] regs NEON registers storing 16bit IQ samples of the PRB. -/// -/// \note Each of the input registers stores four unique REs. -static void pack_prb_9b_big_endian(compressed_prb& c_prb, int16x8x3_t regs) -{ - static constexpr unsigned bytes_per_half_reg = 8; - - // Pack input registers. - uint8x16_t res_packed_bytes_0_u8 = pack_neon_register_9b_big_endian(regs.val[0]); - uint8x16_t res_packed_bytes_1_u8 = pack_neon_register_9b_big_endian(regs.val[1]); - uint8x16_t res_packed_bytes_2_u8 = pack_neon_register_9b_big_endian(regs.val[2]); - - uint8_t* data = c_prb.get_byte_buffer().data(); - - // Store first 9 bytes of every register storing packed bytes. - vst1_u64(reinterpret_cast(data), vreinterpret_u64_u8(vget_low_u8(res_packed_bytes_0_u8))); - vst1q_lane_u8(data + bytes_per_half_reg, res_packed_bytes_0_u8, bytes_per_half_reg); - data += bytes_per_half_reg + 1; - - vst1_u64(reinterpret_cast(data), vreinterpret_u64_u8(vget_low_u8(res_packed_bytes_1_u8))); - vst1q_lane_u8(data + bytes_per_half_reg, res_packed_bytes_1_u8, bytes_per_half_reg); - data += bytes_per_half_reg + 1; - - vst1_u64(reinterpret_cast(data), vreinterpret_u64_u8(vget_low_u8(res_packed_bytes_2_u8))); - vst1q_lane_u8(data + bytes_per_half_reg, res_packed_bytes_2_u8, bytes_per_half_reg); - - c_prb.set_stored_size(BYTES_PER_PRB_9BIT_COMPRESSION); -} - -void neon::pack_prb_big_endian(ofh::compressed_prb& c_prb, int16x8x3_t regs, unsigned iq_width) -{ - if (iq_width == 9) { - return pack_prb_9b_big_endian(c_prb, regs); - } - report_fatal_error("Unsupported bit width"); -} - -/// \brief Unpacks packed 9bit IQ samples stored as bytes in big-endian format to an array of 16bit signed values. -/// -/// \param[out] unpacked_iq_data A sequence of 24 integers, corresponding to \c NOF_CARRIERS_PER_RB unpacked IQ pairs. -/// \param[in] packed_data A sequence of \c BYTES_PER_PRB_9BIT_COMPRESSION packed bytes. -static void unpack_prb_9b_big_endian(span unpacked_iq_data, span packed_data) -{ - // Load input (we need two NEON register to load 27 bytes). - uint8x16x2_t packed_vec_u8x2; - packed_vec_u8x2.val[0] = vld1q_u8(packed_data.data()); - packed_vec_u8x2.val[1] = vld1q_u8(packed_data.data() + 16); - - // Duplicate input words (it is required since below in the code every byte will be used twice: - // to provide MSB bits of the current IQ sample and LSB bits of the previous IQ sample). - uint8x16_t tmp_packed_0_u8 = - vqtbl2q_u8(packed_vec_u8x2, vcombine_u8(vcreate_u8(0x0304020301020001), vcreate_u8(0x0708060705060405))); - uint8x16_t tmp_packed_1_u8 = - vqtbl2q_u8(packed_vec_u8x2, vcombine_u8(vcreate_u8(0x0c0d0b0c0a0b090a), vcreate_u8(0x10110f100e0f0d0e))); - uint8x16_t tmp_packed_2_u8 = - vqtbl2q_u8(packed_vec_u8x2, vcombine_u8(vcreate_u8(0x1516141513141213), vcreate_u8(0x191a181917181617))); - - // Shift left to align to 16bit boundary. - const int16x8_t shl_mask_s16 = vcombine_s16(vcreate_s16(0x0003000200010000), vcreate_s16(0x0007000600050004)); - uint16x8_t shl_tmp_packed_0_u8 = vshlq_u16(vreinterpretq_u16_u8(tmp_packed_0_u8), shl_mask_s16); - uint16x8_t shl_tmp_packed_1_u8 = vshlq_u16(vreinterpretq_u16_u8(tmp_packed_1_u8), shl_mask_s16); - uint16x8_t shl_tmp_packed_2_u8 = vshlq_u16(vreinterpretq_u16_u8(tmp_packed_2_u8), shl_mask_s16); - - // Arithmetically shift right by 7 positions to put bits of interest into LSB positions while preserving the sign. - int16x8_t unpacked_data_0_s16 = vshrq_n_s16(vreinterpretq_s16_u16(shl_tmp_packed_0_u8), 7); - int16x8_t unpacked_data_1_s16 = vshrq_n_s16(vreinterpretq_s16_u16(shl_tmp_packed_1_u8), 7); - int16x8_t unpacked_data_2_s16 = vshrq_n_s16(vreinterpretq_s16_u16(shl_tmp_packed_2_u8), 7); - - // Write results to the output buffer. - vst1q_s16(unpacked_iq_data.data(), unpacked_data_0_s16); - vst1q_s16(unpacked_iq_data.data() + 8, unpacked_data_1_s16); - vst1q_s16(unpacked_iq_data.data() + 16, unpacked_data_2_s16); -} - -void neon::unpack_prb_big_endian(span unpacked_iq_data, span packed_data, unsigned iq_width) -{ - if (iq_width == 9) { - return unpack_prb_9b_big_endian(unpacked_iq_data, packed_data); - } - report_fatal_error("Unsupported bit width"); -} diff --git a/lib/ofh/compression/packing_utils_neon.h b/lib/ofh/compression/packing_utils_neon.h index cb9a2d6c0f..24de3abae1 100644 --- a/lib/ofh/compression/packing_utils_neon.h +++ b/lib/ofh/compression/packing_utils_neon.h @@ -12,30 +12,156 @@ #include "neon_helpers.h" #include "srsran/ofh/compression/compressed_prb.h" +#include "srsran/support/error_handling.h" namespace srsran { namespace ofh { namespace neon { +/// \brief Reads eight 16bit IQ values from input NEON register and packs them to the first 72 bits of the output NEON +/// register in big-endian format, thus occupying 9 output bytes. +/// +/// \param[in] regs NEON register storing 16bit IQ samples of a resource block. +/// \return NEON register storing 9 packed bytes. +inline uint8x16_t pack_neon_register_9b_big_endian(int16x8_t reg) +{ + // Input IQ samples need to be shifted in order to align bits before final packing. + // 0: i0 0 0 0 0 0 0 0 i8 i7 i6 i5 i4 i3 i2 i1 <- rotate right by 1 (shift left by 7, swap bytes later) + // 1: 0 q8 q7 q6 q5 q4 q3 q2 q1 q0 0 0 0 0 0 0 <- shift left by 6 + // 2: 0 0 i8 i7 i6 i5 i4 i3 i2 i1 i0 0 0 0 0 0 <- shift left by 5 + // 3: 0 0 0 q8 q7 q6 q5 q4 q3 q2 q1 q0 0 0 0 0 <- shift left by 4 + // 4: 0 0 0 0 i8 i7 i6 i5 i4 i3 i2 i1 i0 0 0 0 <- shift left by 3 + // 5: 0 0 0 0 0 q8 q7 q6 q5 q4 q3 q2 q1 q0 0 0 <- shift left by 2 + // 6: 0 0 0 0 0 0 i8 i7 i6 i5 i4 i3 i2 i1 i0 0 <- shift left by 1 + // 7: 0 0 0 0 0 0 0 q8 q7 q6 q5 q4 q3 q2 q1 q0 <- no shift + + // Shift data according to the mask described above. + const int16x8_t shift_mask_s16 = vcombine_s16(vcreate_s16(0x0004000500060007), vcreate_s16(0x0000000100020003)); + int16x8_t iq_shl_s16 = vshlq_s16(reg, shift_mask_s16); + + // Mask 16bit words to keep only 9 shifted bits. + const int16x8_t mask_s16 = vcombine_s16(vcreate_s16(0x1ff03fe07fc0ff80), vcreate_s16(0x01ff03fe07fc0ff8)); + iq_shl_s16 = vandq_s16(iq_shl_s16, mask_s16); + + // Shuffle it and create two new vectors that can be OR'ed to produce final result. Temporal vectors look as follows: + // 0 0 0 0 0 0 0 0 | i0 0 0 0 0 0 0 0 | q1 q0 0 0 0 0 0 0 | i2 i1 i0 0 0 0 0 0 | ... + // i8 i7 i6 i5 i4 i3 i2 i1 | 0 q8 q7 q6 q5 q4 q3 q2 | 0 0 i8 i7 i6 i5 i4 i3 | 0 0 0 q8 q7 q6 q5 q4 | ... + int8x16_t iq_shl_s8 = vreinterpretq_s8_s16(iq_shl_s16); + int8x16_t tmp_iq_0_s8 = + vqtbl1q_s8(iq_shl_s8, vcombine_u8(vcreate_u8(0x0c0a0806040200ff), vcreate_u8(0xffffffffffffff0e))); + int8x16_t tmp_iq_1_s8 = + vqtbl1q_s8(iq_shl_s8, vcombine_u8(vcreate_u8(0x0f0d0b0907050301), vcreate_u8(0xffffffffffffffff))); + + // Perform 'bitwise OR'. + return vorrq_u8(vreinterpretq_u8_s8(tmp_iq_0_s8), vreinterpretq_u8_s8(tmp_iq_1_s8)); +} + +/// \brief Packs 16bit IQ values of the PRB using given bit width and big-endian format. +/// +/// \param[out] c_prb Compressed PRB object storing packed bytes. +/// \param[in] regs NEON registers storing 16bit IQ samples of the PRB. +/// +/// \note Each of the input registers stores four unique REs. +inline void pack_prb_9b_big_endian(compressed_prb& c_prb, int16x8x3_t regs) +{ + /// Number of bytes used by 1 packed PRB with IQ samples compressed to 9 bits. + static constexpr unsigned BYTES_PER_PRB_9BIT_COMPRESSION = 27; + + static constexpr unsigned bytes_per_half_reg = 8; + + // Pack input registers. + uint8x16_t res_packed_bytes_0_u8 = pack_neon_register_9b_big_endian(regs.val[0]); + uint8x16_t res_packed_bytes_1_u8 = pack_neon_register_9b_big_endian(regs.val[1]); + uint8x16_t res_packed_bytes_2_u8 = pack_neon_register_9b_big_endian(regs.val[2]); + + uint8_t* data = c_prb.get_byte_buffer().data(); + + // Store first 9 bytes of every register storing packed bytes. + vst1_u64(reinterpret_cast(data), vreinterpret_u64_u8(vget_low_u8(res_packed_bytes_0_u8))); + vst1q_lane_u8(data + bytes_per_half_reg, res_packed_bytes_0_u8, bytes_per_half_reg); + data += bytes_per_half_reg + 1; + + vst1_u64(reinterpret_cast(data), vreinterpret_u64_u8(vget_low_u8(res_packed_bytes_1_u8))); + vst1q_lane_u8(data + bytes_per_half_reg, res_packed_bytes_1_u8, bytes_per_half_reg); + data += bytes_per_half_reg + 1; + + vst1_u64(reinterpret_cast(data), vreinterpret_u64_u8(vget_low_u8(res_packed_bytes_2_u8))); + vst1q_lane_u8(data + bytes_per_half_reg, res_packed_bytes_2_u8, bytes_per_half_reg); + + c_prb.set_stored_size(BYTES_PER_PRB_9BIT_COMPRESSION); +} + /// \brief Packs 16bit IQ values of a resource block using the specified width and big-endian format. /// /// \param[out] c_prb Output PRB storing compressed packed bytes. /// \param[in] reg Vector of three NEON registers storing 16bit IQ pairs of the PRB. /// \param[in] iq_width Bit width of the resulting packed IQ samples. -void pack_prb_big_endian(ofh::compressed_prb& c_prb, int16x8x3_t regs, unsigned iq_width); +void pack_prb_big_endian(ofh::compressed_prb& c_prb, int16x8x3_t regs, unsigned iq_width) +{ + if (iq_width == 9) { + return pack_prb_9b_big_endian(c_prb, regs); + } + report_fatal_error("Unsupported bit width"); +} + +/// \brief Unpacks packed 9bit IQ samples stored as bytes in big-endian format to an array of 16bit signed values. +/// +/// \param[out] unpacked_iq_data A sequence of 24 integers, corresponding to \c NOF_CARRIERS_PER_RB unpacked IQ pairs. +/// \param[in] packed_data A sequence of 27 packed bytes. +inline void unpack_prb_9b_big_endian(span unpacked_iq_data, span packed_data) +{ + // Load input (we need two NEON register to load 27 bytes). + uint8x16x2_t packed_vec_u8x2; + packed_vec_u8x2.val[0] = vld1q_u8(packed_data.data()); + packed_vec_u8x2.val[1] = vld1q_u8(packed_data.data() + 16); + + // Duplicate input words (it is required since below in the code every byte will be used twice: + // to provide MSB bits of the current IQ sample and LSB bits of the previous IQ sample). + uint8x16_t tmp_packed_0_u8 = + vqtbl2q_u8(packed_vec_u8x2, vcombine_u8(vcreate_u8(0x0304020301020001), vcreate_u8(0x0708060705060405))); + uint8x16_t tmp_packed_1_u8 = + vqtbl2q_u8(packed_vec_u8x2, vcombine_u8(vcreate_u8(0x0c0d0b0c0a0b090a), vcreate_u8(0x10110f100e0f0d0e))); + uint8x16_t tmp_packed_2_u8 = + vqtbl2q_u8(packed_vec_u8x2, vcombine_u8(vcreate_u8(0x1516141513141213), vcreate_u8(0x191a181917181617))); + + // Shift left to align to 16bit boundary. + const int16x8_t shl_mask_s16 = vcombine_s16(vcreate_s16(0x0003000200010000), vcreate_s16(0x0007000600050004)); + uint16x8_t shl_tmp_packed_0_u8 = vshlq_u16(vreinterpretq_u16_u8(tmp_packed_0_u8), shl_mask_s16); + uint16x8_t shl_tmp_packed_1_u8 = vshlq_u16(vreinterpretq_u16_u8(tmp_packed_1_u8), shl_mask_s16); + uint16x8_t shl_tmp_packed_2_u8 = vshlq_u16(vreinterpretq_u16_u8(tmp_packed_2_u8), shl_mask_s16); + + // Arithmetically shift right by 7 positions to put bits of interest into LSB positions while preserving the sign. + int16x8_t unpacked_data_0_s16 = vshrq_n_s16(vreinterpretq_s16_u16(shl_tmp_packed_0_u8), 7); + int16x8_t unpacked_data_1_s16 = vshrq_n_s16(vreinterpretq_s16_u16(shl_tmp_packed_1_u8), 7); + int16x8_t unpacked_data_2_s16 = vshrq_n_s16(vreinterpretq_s16_u16(shl_tmp_packed_2_u8), 7); + + // Write results to the output buffer. + vst1q_s16(unpacked_iq_data.data(), unpacked_data_0_s16); + vst1q_s16(unpacked_iq_data.data() + 8, unpacked_data_1_s16); + vst1q_s16(unpacked_iq_data.data() + 16, unpacked_data_2_s16); +} /// \brief Unpacks packed IQ samples stored as bytes in big-endian format to an array of 16bit signed values. /// /// \param[out] unpacked_iq_data A sequence of 24 integers, corresponding to \c NOF_CARRIERS_PER_RB unpacked IQ pairs. /// \param[in] packed_data A sequence of input packed bytes. /// \param[in] iq_width Bit width of the packed IQ samples. -void unpack_prb_big_endian(span unpacked_iq_data, span packed_data, unsigned iq_width); +inline void unpack_prb_big_endian(span unpacked_iq_data, span packed_data, unsigned iq_width) +{ + if (iq_width == 9) { + return unpack_prb_9b_big_endian(unpacked_iq_data, packed_data); + } + report_fatal_error("Unsupported bit width"); +} /// \brief Checks whether the requested bit width is supported by the NEON implementation. /// \param[in] iq_width Requested bit width. /// /// \return True in case packing/unpacking with the requested bit width is supported. -bool iq_width_packing_supported(unsigned iq_width); +inline bool iq_width_packing_supported(unsigned iq_width) +{ + return iq_width == 9; +} } // namespace neon } // namespace ofh diff --git a/tests/benchmarks/ofh/ofh_compression_benchmark.cpp b/tests/benchmarks/ofh/ofh_compression_benchmark.cpp index 953971b58b..b2dfc5b516 100644 --- a/tests/benchmarks/ofh/ofh_compression_benchmark.cpp +++ b/tests/benchmarks/ofh/ofh_compression_benchmark.cpp @@ -33,7 +33,7 @@ static void usage(const char* prog) { fmt::print("Usage: {} [-R repetitions] [-T compression type] [-F factory type] [-s silent]\n", prog); fmt::print("\t-R Repetitions [Default {}]\n", nof_repetitions); - fmt::print("\t-T Type of compression [{'none', 'bfp'}, default is {}]\n", method); + fmt::print("\t-T Type of compression [{{'none', 'bfp'}}, default is {}]\n", method); fmt::print("\t-F Select compression factory [Default {}]\n", impl_type); fmt::print("\t-B Channel bandwidth [Default {}]\n", bw); fmt::print("\t-C Subcarrier spacing. [Default {}]\n", to_string(scs)); From b3d107a91094c05ef6882d9106837f94463af0ba Mon Sep 17 00:00:00 2001 From: qarlosalberto Date: Thu, 22 Feb 2024 16:38:48 +0100 Subject: [PATCH 003/140] ci: 1 ue reest, zmq labels host --- .gitlab/ci/e2e.yml | 1 + .gitlab/ci/e2e/.env | 2 ++ .gitlab/ci/e2e/retina_request_test_mode.yml | 4 ++++ .gitlab/ci/e2e/retina_request_zmq.yml | 6 ++++++ .gitlab/ci/e2e/retina_request_zmq_4x4_mimo.yml | 6 ++++++ .gitlab/ci/e2e/retina_request_zmq_single_ue.yml | 6 ++++++ .gitlab/ci/e2e/retina_request_zmq_srsue.yml | 6 ++++++ tests/e2e/tests/iperf.py | 1 + tests/e2e/tests/reestablishment.py | 6 +++--- 9 files changed, 35 insertions(+), 3 deletions(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 4d56301277..cd5c2762dc 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -143,6 +143,7 @@ e2e request validation: - retina-delete-orchestration-network --user-name ^ci_${GROUP} --regex # Add extra secret env variables to the .env file - | + echo "" >> .gitlab/ci/e2e/.env cat $RETINA_SECRET_ENV >> .gitlab/ci/e2e/.env # Set username for retina - | diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index 17c0aa238c..b0095dcd8c 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -7,3 +7,5 @@ OPEN5GS_VERSION=2.6.1 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin METRICS_SERVER_VERSION=1.5.2 DPDK_VERSION=23.11 +ZMQ_HOSTLABEL_0=kubernetes.io/hostname=k8s-worker-vm2 +ZMQ_HOSTLABEL_1=kubernetes.io/hostname=k8s-worker-vm2 diff --git a/.gitlab/ci/e2e/retina_request_test_mode.yml b/.gitlab/ci/e2e/retina_request_test_mode.yml index ffa7047339..0b16ca52c0 100644 --- a/.gitlab/ci/e2e/retina_request_test_mode.yml +++ b/.gitlab/ci/e2e/retina_request_test_mode.yml @@ -9,6 +9,8 @@ - name: srs-gnb type: gnb image: ${RETINA_REGISTRY_PREFIX}/srsgnb:${RETINA_VERSION} + labels: + - ${ZMQ_HOSTLABEL_0} requirements: arch: amd64 cpu: @@ -41,3 +43,5 @@ requests: "6G" limits: "6G" image: ${RETINA_REGISTRY_PREFIX}/open5gs:${OPEN5GS_VERSION}_${RETINA_VERSION} + labels: + - ${ZMQ_HOSTLABEL_0} diff --git a/.gitlab/ci/e2e/retina_request_zmq.yml b/.gitlab/ci/e2e/retina_request_zmq.yml index 3eca2f3699..12b5fea347 100644 --- a/.gitlab/ci/e2e/retina_request_zmq.yml +++ b/.gitlab/ci/e2e/retina_request_zmq.yml @@ -9,6 +9,8 @@ - name: amarisoft-ue type: ue image: ${RETINA_REGISTRY_PREFIX}/amarisoftue:${AMARISOFT_VERSION}_${RETINA_VERSION} + labels: + - ${ZMQ_HOSTLABEL_1} nof_ports: 32 requirements: arch: amd64 @@ -31,6 +33,8 @@ - name: srs-gnb type: gnb image: ${RETINA_REGISTRY_PREFIX}/srsgnb:${RETINA_VERSION} + labels: + - ${ZMQ_HOSTLABEL_1} requirements: arch: amd64 cpu: @@ -62,3 +66,5 @@ requests: "6G" limits: "6G" image: ${RETINA_REGISTRY_PREFIX}/open5gs:${OPEN5GS_VERSION}_${RETINA_VERSION} + labels: + - ${ZMQ_HOSTLABEL_1} diff --git a/.gitlab/ci/e2e/retina_request_zmq_4x4_mimo.yml b/.gitlab/ci/e2e/retina_request_zmq_4x4_mimo.yml index b9ae6f43d3..1602839879 100644 --- a/.gitlab/ci/e2e/retina_request_zmq_4x4_mimo.yml +++ b/.gitlab/ci/e2e/retina_request_zmq_4x4_mimo.yml @@ -9,6 +9,8 @@ - name: amarisoft-ue type: ue image: ${RETINA_REGISTRY_PREFIX}/amarisoftue:${AMARISOFT_VERSION}_${RETINA_VERSION} + labels: + - ${ZMQ_HOSTLABEL_1} requirements: arch: amd64 cpu: @@ -31,6 +33,8 @@ - name: srs-gnb type: gnb image: ${RETINA_REGISTRY_PREFIX}/srsgnb:${RETINA_VERSION} + labels: + - ${ZMQ_HOSTLABEL_1} requirements: arch: amd64 cpu: @@ -63,3 +67,5 @@ requests: "6G" limits: "6G" image: ${RETINA_REGISTRY_PREFIX}/open5gs:${OPEN5GS_VERSION}_${RETINA_VERSION} + labels: + - ${ZMQ_HOSTLABEL_1} diff --git a/.gitlab/ci/e2e/retina_request_zmq_single_ue.yml b/.gitlab/ci/e2e/retina_request_zmq_single_ue.yml index 9ce41af239..4f6dd88928 100644 --- a/.gitlab/ci/e2e/retina_request_zmq_single_ue.yml +++ b/.gitlab/ci/e2e/retina_request_zmq_single_ue.yml @@ -9,6 +9,8 @@ - name: amarisoft-ue type: ue image: ${RETINA_REGISTRY_PREFIX}/amarisoftue:${AMARISOFT_VERSION}_${RETINA_VERSION} + labels: + - ${ZMQ_HOSTLABEL_1} requirements: arch: amd64 cpu: @@ -30,6 +32,8 @@ - name: srs-gnb type: gnb image: ${RETINA_REGISTRY_PREFIX}/srsgnb:${RETINA_VERSION} + labels: + - ${ZMQ_HOSTLABEL_1} requirements: arch: amd64 cpu: @@ -61,3 +65,5 @@ requests: "6G" limits: "6G" image: ${RETINA_REGISTRY_PREFIX}/open5gs:${OPEN5GS_VERSION}_${RETINA_VERSION} + labels: + - ${ZMQ_HOSTLABEL_1} diff --git a/.gitlab/ci/e2e/retina_request_zmq_srsue.yml b/.gitlab/ci/e2e/retina_request_zmq_srsue.yml index 640663ea18..5c78097cef 100644 --- a/.gitlab/ci/e2e/retina_request_zmq_srsue.yml +++ b/.gitlab/ci/e2e/retina_request_zmq_srsue.yml @@ -9,6 +9,8 @@ - name: srs-ue type: ue image: ${RETINA_REGISTRY_PREFIX}/srsue:${SRSUE_VERSION}_${RETINA_VERSION} + labels: + - ${ZMQ_HOSTLABEL_1} requirements: arch: amd64 cpu: @@ -22,6 +24,8 @@ - name: srs-gnb type: gnb image: ${RETINA_REGISTRY_PREFIX}/srsgnb:${RETINA_VERSION} + labels: + - ${ZMQ_HOSTLABEL_1} requirements: arch: amd64 cpu: @@ -53,3 +57,5 @@ requests: "6G" limits: "6G" image: ${RETINA_REGISTRY_PREFIX}/open5gs:${OPEN5GS_VERSION}_${RETINA_VERSION} + labels: + - ${ZMQ_HOSTLABEL_1} diff --git a/tests/e2e/tests/iperf.py b/tests/e2e/tests/iperf.py index d46cdee3ab..5022063715 100644 --- a/tests/e2e/tests/iperf.py +++ b/tests/e2e/tests/iperf.py @@ -348,6 +348,7 @@ def test_android_hp( (param(41, 30, 20, id="band:%s-scs:%s-bandwidth:%s"),), ) @mark.zmq_4x4_mimo +@mark.flaky(reruns=1, only_rerun=["5GC crashed"]) # pylint: disable=too-many-arguments def test_zmq_4x4_mimo( retina_manager: RetinaTestManager, diff --git a/tests/e2e/tests/reestablishment.py b/tests/e2e/tests/reestablishment.py index f0664206ec..f649faf280 100644 --- a/tests/e2e/tests/reestablishment.py +++ b/tests/e2e/tests/reestablishment.py @@ -11,7 +11,7 @@ """ import logging import time -from typing import Optional, Sequence, Tuple, Union +from typing import Optional, Sequence, Union from pytest import mark from retina.client.manager import RetinaTestManager @@ -38,7 +38,7 @@ def test_zmq_reestablishment( retina_manager: RetinaTestManager, retina_data: RetinaTestData, - ue_4: Tuple[UEStub, ...], + ue: UEStub, # pylint: disable=invalid-name fivegc: FiveGCStub, gnb: GNBStub, band: int, @@ -57,7 +57,7 @@ def test_zmq_reestablishment( _ping_and_reestablishment_multi_ues( retina_manager=retina_manager, retina_data=retina_data, - ue_array=ue_4, + ue_array=(ue,), gnb=gnb, fivegc=fivegc, band=band, From 3491bfe3df693ddc960b51a94949a0a110a74eb9 Mon Sep 17 00:00:00 2001 From: faluco Date: Wed, 21 Feb 2024 12:20:58 +0100 Subject: [PATCH 004/140] byte_buffer: Add no discard attribute to all methods that allocate and may fail spuriously. Update all users of the class that rely on this and error out gracefully --- apps/examples/du/du_example.cpp | 5 +- include/srsran/adt/byte_buffer.h | 58 ++++++------ include/srsran/adt/byte_buffer_chain.h | 34 ++++--- lib/e2/e2sm/e2sm_rc/e2sm_rc_asn1_packer.cpp | 15 +++- lib/e2/procedures/e2_indication_procedure.cpp | 10 ++- lib/mac/mac_ul/pdu_rx_handler.cpp | 12 ++- lib/ngap/ngap_asn1_converters.h | 54 +++++++---- lib/ngap/ngap_asn1_helpers.h | 90 +++++++++++++------ lib/ngap/ngap_impl.cpp | 26 ++++-- .../ngap_initial_context_setup_procedure.cpp | 5 +- ..._pdu_session_resource_modify_procedure.cpp | 6 +- ...pdu_session_resource_release_procedure.cpp | 8 +- lib/rlc/rlc_rx_am_entity.cpp | 6 +- lib/rlc/rlc_rx_um_entity.cpp | 6 +- lib/rrc/ue/procedures/rrc_setup_procedure.cpp | 5 +- lib/rrc/ue/rrc_asn1_helpers.h | 9 +- lib/support/byte_buffer.cpp | 15 ++-- .../benchmarks/du_high/du_high_benchmark.cpp | 5 +- .../unittests/adt/byte_buffer_chain_test.cpp | 30 +++---- tests/unittests/adt/byte_buffer_test.cpp | 16 ++-- .../cu_cp/du_processor_test_messages.cpp | 3 +- tests/unittests/e2/common/e2_test_helpers.h | 24 +++-- tests/unittests/ngap/ngap_test_messages.cpp | 14 +-- tests/unittests/rlc/rlc_um_test.cpp | 24 ++--- tests/unittests/rrc/rrc_ue_test_helpers.h | 3 +- 25 files changed, 310 insertions(+), 173 deletions(-) diff --git a/apps/examples/du/du_example.cpp b/apps/examples/du/du_example.cpp index ae501a61d8..9b095841e3 100644 --- a/apps/examples/du/du_example.cpp +++ b/apps/examples/du/du_example.cpp @@ -247,7 +247,10 @@ class dummy_cu_cp_handler : public f1c_connection_client // Store the packed RRC setup message in the RRC container field of the F1 DL RRC Message that is sent to the // DU. - resp->rrc_container.resize(msg4_pdu.length()); + if (!resp->rrc_container.resize(msg4_pdu.length())) { + du_logger.warning("Unable to resize RRC PDU to {} bytes", msg4_pdu.length()); + return; + } std::copy(msg4_pdu.begin(), msg4_pdu.end(), resp->rrc_container.begin()); } else if (msg.pdu.init_msg().value.type().value == asn1::f1ap::f1ap_elem_procs_o::init_msg_c::types_opts::f1_setup_request) { diff --git a/include/srsran/adt/byte_buffer.h b/include/srsran/adt/byte_buffer.h index 9560ee3a5a..3ebb4847c2 100644 --- a/include/srsran/adt/byte_buffer.h +++ b/include/srsran/adt/byte_buffer.h @@ -28,6 +28,7 @@ void init_byte_buffer_segment_pool(std::size_t nof_segments, std::size_t memory_block_size = byte_buffer_segment_pool_default_segment_size()); /// \brief Non-owning view to a byte sequence. +/// /// The underlying byte sequence is not contiguous in memory. Instead, it is represented as an intrusive linked list of /// byte buffer segments, where each segment contains a span of bytes. class byte_buffer_view @@ -97,8 +98,7 @@ class byte_buffer_view const_byte_buffer_segment_span_range segments() const { return {it, length()}; } /// Returns a non-owning list of segments that compose the byte_buffer. - /// The segments are not const, so that the callee can modify the bytes, - /// but not layout of the buffer. + /// The segments are not const, so that the callee can modify the bytes, but not layout of the buffer. byte_buffer_segment_span_range modifiable_segments() { return {it, length()}; }; /// \brief Equality comparison between byte buffer view and another range. @@ -131,6 +131,7 @@ class byte_buffer_view class byte_buffer_slice; /// \brief Byte sequence, which represents its data in memory via an intrusive linked list of memory chunks. +/// /// This container is not contiguous in memory. /// Default copy ctor and assignment is disabled in this container. The user should instead std::move to transfer /// ownership, .copy() for shallow copies with shared ownership and .deep_copy() for byte-wise copies. @@ -176,7 +177,7 @@ class byte_buffer } } - /// Creates a byte_buffer with data intialized via a initializer list. + /// Creates a byte_buffer with data initialized via a initializer list. byte_buffer(std::initializer_list lst) : byte_buffer(span{lst.begin(), lst.size()}) {} /// Creates a byte_buffer with data assigned from a range of bytes. @@ -191,7 +192,7 @@ class byte_buffer /// Move constructor. byte_buffer(byte_buffer&& other) noexcept = default; - /// copy assignment is disabled. Use std::move, .copy() or .deep_copy() instead. + /// Copy assignment is disabled. Use std::move, .copy() or .deep_copy() instead. byte_buffer& operator=(const byte_buffer&) noexcept = delete; /// Move assignment of byte_buffer. It avoids unnecessary reference counting increment. @@ -271,9 +272,9 @@ class byte_buffer } /// Appends a view of bytes into current byte buffer. - bool append(const byte_buffer_view& view) + SRSRAN_NODISCARD bool append(const byte_buffer_view& view) { - // append segment by segment. + // Append segment by segment. auto view_segs = view.segments(); for (span seg : view_segs) { if (not append(seg)) { @@ -284,17 +285,17 @@ class byte_buffer } /// Appends an owning view of bytes into current byte buffer. - bool append(const byte_buffer_slice& view); + SRSRAN_NODISCARD bool append(const byte_buffer_slice& view); /// Prepends bytes to byte_buffer. This function may allocate new segments. - bool prepend(span bytes); + SRSRAN_NODISCARD bool prepend(span bytes); /// \brief Prepend data of byte buffer to this byte buffer. - bool prepend(const byte_buffer& other); + SRSRAN_NODISCARD bool prepend(const byte_buffer& other); /// \brief Prepend data of r-value byte buffer to this byte buffer. The segments of the provided byte buffer can get /// "stolen" if the byte buffer is the last reference to the segments. - bool prepend(byte_buffer&& other); + SRSRAN_NODISCARD bool prepend(byte_buffer&& other); /// Prepends space in byte_buffer. This function may allocate new segments. /// \param nof_bytes Number of bytes to reserve at header. @@ -341,20 +342,19 @@ class byte_buffer bool is_contiguous() const { return empty() or ctrl_blk_ptr->segments.head == ctrl_blk_ptr->segments.tail; } /// Moves the bytes stored in different segments of the byte_buffer into first segment. - bool linearize(); + SRSRAN_NODISCARD bool linearize(); /// Set byte_buffer length. Note: It doesn't initialize newly created bytes. - bool resize(size_t new_sz); + SRSRAN_NODISCARD bool resize(size_t new_sz); /// Returns a non-owning list of segments that compose the byte_buffer. byte_buffer_segment_span_range segments() { - return byte_buffer_segment_span_range(ctrl_blk_ptr != nullptr ? ctrl_blk_ptr->segments.head : nullptr, 0, length()); + return {ctrl_blk_ptr != nullptr ? ctrl_blk_ptr->segments.head : nullptr, 0, length()}; } const_byte_buffer_segment_span_range segments() const { - return const_byte_buffer_segment_span_range( - ctrl_blk_ptr != nullptr ? ctrl_blk_ptr->segments.head : nullptr, 0, length()); + return {ctrl_blk_ptr != nullptr ? ctrl_blk_ptr->segments.head : nullptr, 0, length()}; } /// \brief Equality comparison between byte buffer view and another range. @@ -417,11 +417,12 @@ class byte_buffer }; /// \brief This class represents a sub-interval or make_slice of a potentially larger byte_buffer. +/// /// Like byte_buffer and byte_buffer_view, the represented bytes by this class are not contiguous in memory. -/// Contrarily to byte_buffer_view, this class retains shared ownership of the segments held by the byte_buffer -/// which it references. -/// Due to the shared ownership model, the usage of this class may involve additional overhead associated with -/// reference counting, which does not take place when using byte_buffer_view. +/// Contrarily to byte_buffer_view, this class retains shared ownership of the segments held by the byte_buffer which it +/// references. +/// Due to the shared ownership model, the usage of this class may involve additional overhead associated with reference +/// counting, which does not take place when using byte_buffer_view. class byte_buffer_slice { public: @@ -599,13 +600,14 @@ class byte_buffer_writer /// Appends span of bytes. SRSRAN_NODISCARD bool append(span bytes) { return buffer->append(bytes); } - /// Appends single byte. + /// Appends a single byte. SRSRAN_NODISCARD bool append(uint8_t byte) { return buffer->append(byte); } + /// Appends the specified amount of zeros. SRSRAN_NODISCARD bool append_zeros(size_t nof_zeros) { // TODO: optimize. - for (size_t i = 0; i < nof_zeros; ++i) { + for (size_t i = 0; i != nof_zeros; ++i) { if (not buffer->append(0)) { return false; } @@ -630,10 +632,11 @@ class byte_buffer_writer inline byte_buffer make_byte_buffer(const std::string& hex_str) { srsran_assert(hex_str.size() % 2 == 0, "The number of hex digits must be even"); + byte_buffer ret; - for (size_t i = 0; i < hex_str.size(); i += 2) { + for (size_t i = 0, e = hex_str.size(); i != e; i += 2) { uint8_t val; - sscanf(hex_str.data() + i, "%02hhX", &val); + std::sscanf(hex_str.data() + i, "%02hhX", &val); if (not ret.append(val)) { ret.clear(); break; @@ -642,7 +645,7 @@ inline byte_buffer make_byte_buffer(const std::string& hex_str) return ret; } -/// Perfoms a segment-wise copy of the byte_buffer into a span object. +/// Performs a segment-wise copy of the byte_buffer into a span object. /// The length is limited by the length of src and dst, whichever is smaller. /// /// \param src Source byte_buffer. @@ -679,16 +682,17 @@ inline size_t copy_segments(const ByteBufferType& src, span dst) /// \return A contiguous view of the byte_buffer inline span to_span(const byte_buffer& src, span tmp_mem) { - // empty buffer + // Empty buffer. if (src.empty()) { return {}; } - // is contiguous: shortcut without copy + // Is contiguous: shortcut without copy. if (src.is_contiguous()) { return *src.segments().begin(); } - // non-contiguous: copy required + + // Non-contiguous: copy required. srsran_assert(src.length() <= tmp_mem.size(), "Insufficient temporary memory to fit the byte_buffer. buffer_size={}, tmp_size={}", src.length(), diff --git a/include/srsran/adt/byte_buffer_chain.h b/include/srsran/adt/byte_buffer_chain.h index 7058efe3d5..b046465927 100644 --- a/include/srsran/adt/byte_buffer_chain.h +++ b/include/srsran/adt/byte_buffer_chain.h @@ -155,10 +155,18 @@ class byte_buffer_chain byte_buffer_chain(const byte_buffer_chain&) = delete; /// Conversion from byte_buffer to byte_buffer_chain. - explicit byte_buffer_chain(byte_buffer buf_) : byte_buffer_chain() { append(std::move(buf_)); } + explicit byte_buffer_chain(byte_buffer buf_) : byte_buffer_chain() + { + bool ret = append(std::move(buf_)); + (void)ret; + } /// Conversion from byte_buffer_slice to byte_buffer_chain. - byte_buffer_chain(byte_buffer_slice&& buf_) : byte_buffer_chain() { append(std::move(buf_)); } + byte_buffer_chain(byte_buffer_slice&& buf_) : byte_buffer_chain() + { + bool ret = append(std::move(buf_)); + (void)ret; + } /// Conversion from byte_buffer with specified offset and size to byte_buffer_chain. byte_buffer_chain(byte_buffer buf_, size_t start, size_t sz) : @@ -221,7 +229,7 @@ class byte_buffer_chain /// /// \param obj Slice to append to the byte_buffer_chain. /// \return true if operation was successful, false otherwise. - bool append(byte_buffer_slice obj) noexcept + SRSRAN_NODISCARD bool append(byte_buffer_slice obj) noexcept { if (obj.empty()) { return true; @@ -237,11 +245,11 @@ class byte_buffer_chain /// Appends a byte_buffer to the end of the byte_buffer_chain. /// \return true if operation was successful, false otherwise. - bool append(byte_buffer buf) { return append(byte_buffer_slice{std::move(buf)}); } + SRSRAN_NODISCARD bool append(byte_buffer buf) { return append(byte_buffer_slice{std::move(buf)}); } /// Appends the contents of another byte_buffer_chain to the end of this byte_buffer_chain. /// \return true if operation was successful, false otherwise. - bool append(byte_buffer_chain other) + SRSRAN_NODISCARD bool append(byte_buffer_chain other) { if (nof_slices() + other.nof_slices() > max_nof_slices()) { return false; @@ -257,7 +265,7 @@ class byte_buffer_chain /// Prepends a byte_buffer_slice to the beginning of the byte_buffer_chain. This operation has O(N) complexity. /// \return true if operation was successful, false otherwise. - bool prepend(byte_buffer_slice slice) + SRSRAN_NODISCARD bool prepend(byte_buffer_slice slice) { if (slice.empty()) { return true; @@ -276,14 +284,14 @@ class byte_buffer_chain } byte_count += slice.length(); slice_count++; - // Store slice in the first (now empty) position + // Store slice in the first (now empty) position. *slices_ptr = std::move(slice); return true; } /// Prepends a byte_buffer to the beginning of the byte_buffer_chain. /// \return true if operation was successful, false otherwise. - bool prepend(byte_buffer buf) { return prepend(byte_buffer_slice{std::move(buf)}); } + SRSRAN_NODISCARD bool prepend(byte_buffer buf) { return prepend(byte_buffer_slice{std::move(buf)}); } /// Release all the byte buffer slices held by the byte_buffer_chain. void clear() @@ -348,15 +356,15 @@ class byte_buffer_chain void operator()(void* p); }; - // Total number of bytes stored in this container. + /// Total number of bytes stored in this container. size_t byte_count = 0; - // Memory block managed by a memory pool, where the slices are stored. + /// Memory block managed by a memory pool, where the slices are stored. std::unique_ptr mem_block; - // Maximum number of byte_buffer_slices that this container can hold. + /// Maximum number of byte_buffer_slices that this container can hold. size_t max_slices = 0; - // Total number of byte_buffer_slices stored in this container. + /// Total number of byte_buffer_slices stored in this container. size_t slice_count = 0; - // Array where byte_buffer_slices are stored. This array is a view to the \c mem_block. + /// Array where byte_buffer_slices are stored. This array is a view to the \c mem_block. byte_buffer_slice* slices_ptr = nullptr; }; diff --git a/lib/e2/e2sm/e2sm_rc/e2sm_rc_asn1_packer.cpp b/lib/e2/e2sm/e2sm_rc/e2sm_rc_asn1_packer.cpp index a6f0ca035f..ff3d0e0074 100644 --- a/lib/e2/e2sm/e2sm_rc/e2sm_rc_asn1_packer.cpp +++ b/lib/e2/e2sm/e2sm_rc/e2sm_rc_asn1_packer.cpp @@ -87,7 +87,10 @@ e2_ric_control_response e2sm_rc_asn1_packer::pack_ric_control_response(const e2s if (variant_get(e2sm_response.ric_ctrl_outcome).pack(bref) != asn1::SRSASN_SUCCESS) { printf("Failed to pack E2SM RC RIC Control Outcome (Ack)\n"); } - e2_control_response.ack->ri_cctrl_outcome->resize(buf.length()); + if (!e2_control_response.ack->ri_cctrl_outcome->resize(buf.length())) { + printf("Failed to resize E2SM RC RIC Control Outcome (Ack)\n"); + return {}; + } std::copy(buf.begin(), buf.end(), e2_control_response.ack->ri_cctrl_outcome->begin()); } } else { @@ -98,7 +101,10 @@ e2_ric_control_response e2sm_rc_asn1_packer::pack_ric_control_response(const e2s if (variant_get(e2sm_response.ric_ctrl_outcome).pack(bref) != asn1::SRSASN_SUCCESS) { printf("Failed to pack E2SM RC RIC Control Outcome (Failure)\n"); } - e2_control_response.failure->ri_cctrl_outcome->resize(buf.length()); + if (!e2_control_response.failure->ri_cctrl_outcome->resize(buf.length())) { + printf("Failed to resize E2SM RC RIC Control Outcome (Failure)\n"); + return {}; + } std::copy(buf.begin(), buf.end(), e2_control_response.failure->ri_cctrl_outcome->begin()); } e2_control_response.failure->cause.value = e2sm_response.cause; @@ -154,7 +160,10 @@ asn1::unbounded_octstring e2sm_rc_asn1_packer::pack_ran_function_descripti return ran_function_description; } - ran_function_description.resize(buf.length()); + if (!ran_function_description.resize(buf.length())) { + printf("Failed to resize E2SM RC RAN Function Description\n"); + return ran_function_description; + } std::copy(buf.begin(), buf.end(), ran_function_description.begin()); return ran_function_description; } diff --git a/lib/e2/procedures/e2_indication_procedure.cpp b/lib/e2/procedures/e2_indication_procedure.cpp index 12eb967933..8c23cbc512 100644 --- a/lib/e2/procedures/e2_indication_procedure.cpp +++ b/lib/e2/procedures/e2_indication_procedure.cpp @@ -75,9 +75,15 @@ void e2_indication_procedure::operator()(coro_context>& c } // Put RIC indication content into message. - e2_ind.indication->ri_cind_msg.value.resize(ind_msg_bytes.length()); + if (!e2_ind.indication->ri_cind_msg.value.resize(ind_msg_bytes.length())) { + logger.error("Unable to resize byte_buffer, dropping indication"); + continue; + } std::copy(ind_msg_bytes.begin(), ind_msg_bytes.end(), e2_ind.indication->ri_cind_msg.value.begin()); - e2_ind.indication->ri_cind_hdr.value.resize(ind_hdr_bytes.length()); + if (!e2_ind.indication->ri_cind_hdr.value.resize(ind_hdr_bytes.length())) { + logger.error("Unable to resize byte_buffer, dropping indication"); + continue; + } std::copy(ind_hdr_bytes.begin(), ind_hdr_bytes.end(), e2_ind.indication->ri_cind_hdr.value.begin()); logger.info("Sending E2 indication"); send_e2_indication(e2_ind); diff --git a/lib/mac/mac_ul/pdu_rx_handler.cpp b/lib/mac/mac_ul/pdu_rx_handler.cpp index 2e62fb811b..3a4d455dfb 100644 --- a/lib/mac/mac_ul/pdu_rx_handler.cpp +++ b/lib/mac/mac_ul/pdu_rx_handler.cpp @@ -118,7 +118,7 @@ bool pdu_rx_handler::push_ul_ccch_msg(du_ue_index_t ue_index, byte_buffer ul_ccc { mac_ul_ue_context* ue = ue_manager.find_ue(ue_index); if (ue == nullptr) { - logger.warning("UL subPDU ue={}, lcid={} UL-CCCH: Received UL-CCCH for inexistent UE", ue_index, LCID_SRB0); + logger.warning("UL subPDU ue={}, lcid={} UL-CCCH: Received UL-CCCH for non-existent UE", ue_index, LCID_SRB0); return false; } @@ -159,13 +159,13 @@ bool pdu_rx_handler::handle_rx_subpdus(const decoded_mac_rx_pdu& ctx) bool pdu_rx_handler::handle_sdu(const decoded_mac_rx_pdu& ctx, const mac_ul_sch_subpdu& sdu, mac_ul_ue_context* ue) { if (ue == nullptr) { - logger.warning("{}: Discarding SDU. Cause: Inexistent C-RNTI", create_prefix(ctx, sdu)); + logger.warning("{}: Discarding SDU. Cause: Non-existent C-RNTI", create_prefix(ctx, sdu)); return false; } lcid_t lcid = (lcid_t)sdu.lcid().value(); if (not ue->ul_bearers.contains(lcid)) { - logger.warning("{}: Discarding SDU. Cause: Inexistent LCID", create_prefix(ctx, sdu)); + logger.warning("{}: Discarding SDU. Cause: Non-existent LCID", create_prefix(ctx, sdu)); return false; } @@ -278,7 +278,11 @@ bool pdu_rx_handler::handle_ccch_msg(const decoded_mac_rx_pdu& ctx, const mac_ul msg.tc_rnti = ctx.pdu_rx.rnti; msg.cell_index = ctx.cell_index_rx; msg.slot_rx = ctx.slot_rx; - msg.subpdu.append(sdu.payload()); + + if (!msg.subpdu.append(sdu.payload())) { + logger.warning("{}: Unable to append SDU into sub-PDU", create_prefix(ctx, sdu)); + return false; + } ccch_notifier.on_ul_ccch_msg_received(msg); // TODO: Do not discard remaining CEs. diff --git a/lib/ngap/ngap_asn1_converters.h b/lib/ngap/ngap_asn1_converters.h index c2bcf866ba..218c870e8e 100644 --- a/lib/ngap/ngap_asn1_converters.h +++ b/lib/ngap/ngap_asn1_converters.h @@ -91,7 +91,7 @@ cu_cp_assoc_qos_flow_to_ngap_assoc_qos_flow_item(cu_cp_associated_qos_flow cu_cp /// \param cu_cp_qos_flow_info The CU-CP QoS Flow Per TNL Info. /// \return The NGAP QoS Flow Per TNL Info. inline asn1::ngap::qos_flow_per_tnl_info_s -cu_cp_qos_flow_per_tnl_info_to_ngap_qos_flow_per_tnl_info(cu_cp_qos_flow_per_tnl_information cu_cp_qos_flow_info) +cu_cp_qos_flow_per_tnl_info_to_ngap_qos_flow_per_tnl_info(const cu_cp_qos_flow_per_tnl_information& cu_cp_qos_flow_info) { asn1::ngap::qos_flow_per_tnl_info_s ngap_qos_flow_info; @@ -213,7 +213,7 @@ cu_cp_user_location_info_to_asn1(const cu_cp_user_location_info_nr& cu_cp_user_l /// \return The humand-readable string. inline std::string asn1_cause_to_string(const asn1::ngap::cause_c& cause) { - std::string cause_str = ""; + std::string cause_str; switch (cause.type()) { case asn1::ngap::cause_c::types_opts::radio_network: @@ -239,13 +239,13 @@ inline std::string asn1_cause_to_string(const asn1::ngap::cause_c& cause) return cause_str; } -/// \brief Convert common type Initial Context Setup Response message to NGAP Initial Context Setup Response -/// message. +/// \brief Convert common type Initial Context Setup Response message to NGAP Initial Context Setup Response message. /// \param[out] resp The ASN1 NGAP Initial Context Setup Response message. /// \param[in] cu_cp_resp The CU-CP Initial Context Setup Response message. +/// \return True on success, otherwise false. template -inline void pdu_session_res_setup_response_item_to_asn1(template_asn1_item& asn1_resp, - const cu_cp_pdu_session_res_setup_response_item resp) +inline bool pdu_session_res_setup_response_item_to_asn1(template_asn1_item& asn1_resp, + const cu_cp_pdu_session_res_setup_response_item& resp) { asn1_resp.pdu_session_id = pdu_session_id_to_uint(resp.pdu_session_id); @@ -281,16 +281,21 @@ inline void pdu_session_res_setup_response_item_to_asn1(template_asn1_item& // Pack pdu_session_res_setup_resp_transfer_s byte_buffer pdu = pack_into_pdu(response_transfer); - asn1_resp.pdu_session_res_setup_resp_transfer.resize(pdu.length()); + if (!asn1_resp.pdu_session_res_setup_resp_transfer.resize(pdu.length())) { + return false; + } std::copy(pdu.begin(), pdu.end(), asn1_resp.pdu_session_res_setup_resp_transfer.begin()); + + return true; } /// \brief Convert common type modify response item to ASN1 type message. /// \param[out] asn1_resp The ASN1 NGAP struct. /// \param[in] resp The common type struct. +/// \return True on success, otherwise false. template -inline void pdu_session_res_modify_response_item_to_asn1(template_asn1_item& asn1_resp, - const cu_cp_pdu_session_resource_modify_response_item resp) +inline bool pdu_session_res_modify_response_item_to_asn1(template_asn1_item& asn1_resp, + const cu_cp_pdu_session_resource_modify_response_item& resp) { asn1_resp.pdu_session_id = pdu_session_id_to_uint(resp.pdu_session_id); @@ -315,16 +320,21 @@ inline void pdu_session_res_modify_response_item_to_asn1(template_asn1_item& asn // Pack pdu_session_res_modify_resp_transfer_s byte_buffer pdu = pack_into_pdu(response_transfer); - asn1_resp.pdu_session_res_modify_resp_transfer.resize(pdu.length()); + if (!asn1_resp.pdu_session_res_modify_resp_transfer.resize(pdu.length())) { + return false; + } std::copy(pdu.begin(), pdu.end(), asn1_resp.pdu_session_res_modify_resp_transfer.begin()); + + return true; } /// \brief Convert common type modify response item to ASN1 type message. /// \param[out] asn1_resp The ASN1 NGAP struct. /// \param[in] resp The common type struct. +/// \return True on success, otherwise false. template -inline void pdu_session_res_failed_to_modify_item_to_asn1(template_asn1_item& asn1_resp, - const cu_cp_pdu_session_resource_failed_to_modify_item resp) +inline bool pdu_session_res_failed_to_modify_item_to_asn1(template_asn1_item& asn1_resp, + const cu_cp_pdu_session_resource_failed_to_modify_item& resp) { asn1_resp.pdu_session_id = pdu_session_id_to_uint(resp.pdu_session_id); @@ -334,17 +344,21 @@ inline void pdu_session_res_failed_to_modify_item_to_asn1(template_asn1_item& as // Pack transfer byte_buffer pdu = pack_into_pdu(response_transfer); - asn1_resp.pdu_session_res_modify_unsuccessful_transfer.resize(pdu.length()); + if (!asn1_resp.pdu_session_res_modify_unsuccessful_transfer.resize(pdu.length())) { + return false; + } std::copy(pdu.begin(), pdu.end(), asn1_resp.pdu_session_res_modify_unsuccessful_transfer.begin()); + + return true; } -/// \brief Convert common type Initial Context Setup Response message to NGAP Initial Context Setup Response -/// message. +/// \brief Convert common type Initial Context Setup Response message to NGAP Initial Context Setup Response message. /// \param[out] resp The ASN1 NGAP Initial Context Setup Response message. /// \param[in] cu_cp_resp The CU-CP Initial Context Setup Response message. +/// \return True on success, otherwise false. template -inline void pdu_session_res_setup_failed_item_to_asn1(template_asn1_item& asn1_resp, - const cu_cp_pdu_session_res_setup_failed_item resp) +inline bool pdu_session_res_setup_failed_item_to_asn1(template_asn1_item& asn1_resp, + const cu_cp_pdu_session_res_setup_failed_item& resp) { asn1_resp.pdu_session_id = pdu_session_id_to_uint(resp.pdu_session_id); @@ -356,8 +370,12 @@ inline void pdu_session_res_setup_failed_item_to_asn1(template_asn1_item& // Pack pdu_session_res_setup_unsuccessful_transfer_s byte_buffer pdu = pack_into_pdu(setup_unsuccessful_transfer); - asn1_resp.pdu_session_res_setup_unsuccessful_transfer.resize(pdu.length()); + if (!asn1_resp.pdu_session_res_setup_unsuccessful_transfer.resize(pdu.length())) { + return false; + } std::copy(pdu.begin(), pdu.end(), asn1_resp.pdu_session_res_setup_unsuccessful_transfer.begin()); + + return true; } /// \brief Convert ASN.1 GUAMI to a common type. diff --git a/lib/ngap/ngap_asn1_helpers.h b/lib/ngap/ngap_asn1_helpers.h index b09516d1bf..9ff673253c 100644 --- a/lib/ngap/ngap_asn1_helpers.h +++ b/lib/ngap/ngap_asn1_helpers.h @@ -186,7 +186,7 @@ inline void fill_asn1_ul_nas_transport(asn1::ngap::ul_nas_transport_s& asn1_msg, template inline bool fill_cu_cp_pdu_session_resource_setup_item_base(cu_cp_pdu_session_res_setup_item& setup_item, const template_asn1_item& asn1_session_item, - const byte_buffer asn1_request_transfer) + byte_buffer asn1_request_transfer) { // pDUSessionID setup_item.pdu_session_id = uint_to_pdu_session_id(asn1_session_item.pdu_session_id); @@ -315,7 +315,9 @@ inline bool fill_cu_cp_pdu_session_resource_setup_request( // pDUSessionNAS-PDU if (!asn1_session_item.pdu_session_nas_pdu.empty()) { - setup_item.pdu_session_nas_pdu.resize(asn1_session_item.pdu_session_nas_pdu.size()); + if (!setup_item.pdu_session_nas_pdu.resize(asn1_session_item.pdu_session_nas_pdu.size())) { + return false; + } std::copy(asn1_session_item.pdu_session_nas_pdu.begin(), asn1_session_item.pdu_session_nas_pdu.end(), setup_item.pdu_session_nas_pdu.begin()); @@ -347,7 +349,9 @@ inline bool fill_cu_cp_pdu_session_resource_setup_request( // NAS-PDU if (!asn1_session_item.nas_pdu.empty()) { - setup_item.pdu_session_nas_pdu.resize(asn1_session_item.nas_pdu.size()); + if (!setup_item.pdu_session_nas_pdu.resize(asn1_session_item.nas_pdu.size())) { + return false; + } std::copy( asn1_session_item.nas_pdu.begin(), asn1_session_item.nas_pdu.end(), setup_item.pdu_session_nas_pdu.begin()); } @@ -436,11 +440,11 @@ inline bool fill_ngap_initial_context_setup_request(ngap_init_context_setup_requ return true; } -/// \brief Convert common type Initial Context Setup Response message to NGAP Initial Context Setup Response -/// message. +/// \brief Convert common type Initial Context Setup Response message to NGAP Initial Context Setup Response message. /// \param[out] asn1_resp The ASN1 NGAP Initial Context Setup Response message. /// \param[in] resp The CU-CP Initial Context Setup Response message. -inline void fill_asn1_initial_context_setup_response(asn1::ngap::init_context_setup_resp_s& asn1_resp, +/// \return True on success, otherwise false. +inline bool fill_asn1_initial_context_setup_response(asn1::ngap::init_context_setup_resp_s& asn1_resp, const ngap_init_context_setup_response& resp) { // Fill PDU Session Resource Setup Response List @@ -450,7 +454,9 @@ inline void fill_asn1_initial_context_setup_response(asn1::ngap::init_context_se for (const auto& resp_item : resp.pdu_session_res_setup_response_items) { asn1::ngap::pdu_session_res_setup_item_cxt_res_s asn1_resp_item; - pdu_session_res_setup_response_item_to_asn1(asn1_resp_item, resp_item); + if (!pdu_session_res_setup_response_item_to_asn1(asn1_resp_item, resp_item)) { + return false; + } asn1_resp->pdu_session_res_setup_list_cxt_res.push_back(asn1_resp_item); } @@ -462,7 +468,9 @@ inline void fill_asn1_initial_context_setup_response(asn1::ngap::init_context_se for (const auto& setup_failed_item : resp.pdu_session_res_failed_to_setup_items) { asn1::ngap::pdu_session_res_failed_to_setup_item_cxt_res_s asn1_setup_failed_item; - pdu_session_res_setup_failed_item_to_asn1(asn1_setup_failed_item, setup_failed_item); + if (!pdu_session_res_setup_failed_item_to_asn1(asn1_setup_failed_item, setup_failed_item)) { + return false; + } asn1_resp->pdu_session_res_failed_to_setup_list_cxt_res.push_back(asn1_setup_failed_item); } @@ -472,6 +480,8 @@ inline void fill_asn1_initial_context_setup_response(asn1::ngap::init_context_se if (resp.crit_diagnostics.has_value()) { // TODO: Add crit diagnostics } + + return true; } /// \brief Convert common type Initial Context Setup Failure message to NGAP Initial Context Setup Failure @@ -502,10 +512,11 @@ inline void fill_asn1_initial_context_setup_failure(asn1::ngap::init_context_set } } -/// \brief Convert a NGAP ASN1 modify item to commong type. +/// \brief Convert a NGAP ASN1 modify item to common type. /// \param[out] modify_item The flat/common version /// \param[in] asn1_session_item The ASN1 struct to be converted. -inline void fill_cu_cp_pdu_session_resource_modify_item_base( +/// \return True on success, otherwise false. +inline bool fill_cu_cp_pdu_session_resource_modify_item_base( cu_cp_pdu_session_res_modify_item_mod_req& modify_item, const asn1::ngap::pdu_session_res_modify_item_mod_req_s& asn1_session_item) { @@ -515,7 +526,7 @@ inline void fill_cu_cp_pdu_session_resource_modify_item_base( asn1::cbit_ref bref(asn1_session_item.pdu_session_res_modify_request_transfer); if (asn1_modify_req_transfer.unpack(bref) != asn1::SRSASN_SUCCESS) { srslog::fetch_basic_logger("NGAP").error("Couldn't unpack PDU Session Resource Modify Request Transfer PDU."); - return; + return false; } if (asn1_modify_req_transfer->qos_flow_add_or_modify_request_list_present) { @@ -574,33 +585,42 @@ inline void fill_cu_cp_pdu_session_resource_modify_item_base( } if (!asn1_session_item.nas_pdu.empty()) { - modify_item.nas_pdu.resize(asn1_session_item.nas_pdu.size()); + if (!modify_item.nas_pdu.resize(asn1_session_item.nas_pdu.size())) { + return false; + } std::copy(asn1_session_item.nas_pdu.begin(), asn1_session_item.nas_pdu.end(), modify_item.nas_pdu.begin()); } + + return true; } /// \brief Convert NGAP ASN1 PDU Session Resource Modify List ASN1 struct to common type. /// \param[out] cu_cp_pdu_session_resource_modify_msg The cu_cp_pdu_session_res_modify_msg struct to fill. /// \param[in] asn1_pdu_session_res_modify_list The pdu_session_res_modify_list ASN1 struct. -inline void fill_cu_cp_pdu_session_resource_modify_request( +/// \return True on success, otherwise false. +inline bool fill_cu_cp_pdu_session_resource_modify_request( cu_cp_pdu_session_resource_modify_request& cu_cp_pdu_session_resource_modify_msg, const asn1::dyn_seq_of& asn1_pdu_session_res_modify_list) { for (const auto& asn1_session_item : asn1_pdu_session_res_modify_list) { cu_cp_pdu_session_res_modify_item_mod_req modify_item; - fill_cu_cp_pdu_session_resource_modify_item_base(modify_item, asn1_session_item); + if (!fill_cu_cp_pdu_session_resource_modify_item_base(modify_item, asn1_session_item)) { + return false; + } cu_cp_pdu_session_resource_modify_msg.pdu_session_res_modify_items.emplace(modify_item.pdu_session_id, std::move(modify_item)); } + + return true; } /// \brief Convert common type PDU Session Resource Setup Response message to NGAP PDU Session Resource Setup Response /// message. /// \param[out] resp The ASN1 NGAP PDU Session Resource Setup Response message. /// \param[in] cu_cp_resp The CU-CP PDU Session Resource Setup Response message. -inline void fill_asn1_pdu_session_res_setup_response(asn1::ngap::pdu_session_res_setup_resp_s& resp, - const cu_cp_pdu_session_resource_setup_response cu_cp_resp) +inline void fill_asn1_pdu_session_res_setup_response(asn1::ngap::pdu_session_res_setup_resp_s& resp, + const cu_cp_pdu_session_resource_setup_response& cu_cp_resp) { // Fill PDU Session Resource Setup Response List if (!cu_cp_resp.pdu_session_res_setup_response_items.empty()) { @@ -631,10 +651,12 @@ inline void fill_asn1_pdu_session_res_setup_response(asn1::ngap::pdu_session_res } /// \brief Convert common type PDU Session Resource Modify Response message to NGAP PDU Session Resource Modify -/// Response message. \param[out] resp The ASN1 NGAP PDU Session Resource Modify Response message. \param[in] -/// cu_cp_resp The CU-CP PDU Session Resource Modify Response message. -inline void fill_asn1_pdu_session_res_modify_response(asn1::ngap::pdu_session_res_modify_resp_s& resp, - const cu_cp_pdu_session_resource_modify_response cu_cp_resp) +/// Response message. +/// \param[out] resp The ASN1 NGAP PDU Session Resource Modify Response message. +/// \param[in] cu_cp_resp The CU-CP PDU Session Resource Modify Response message. +/// \return True on success, otherwise false. +inline bool fill_asn1_pdu_session_res_modify_response(asn1::ngap::pdu_session_res_modify_resp_s& resp, + const cu_cp_pdu_session_resource_modify_response& cu_cp_resp) { // Fill PDU Session Resource Modify Response List if (!cu_cp_resp.pdu_session_res_modify_list.empty()) { @@ -642,7 +664,9 @@ inline void fill_asn1_pdu_session_res_modify_response(asn1::ngap::pdu_session_re for (const auto& cu_cp_resp_item : cu_cp_resp.pdu_session_res_modify_list) { asn1::ngap::pdu_session_res_modify_item_mod_res_s resp_item; - pdu_session_res_modify_response_item_to_asn1(resp_item, cu_cp_resp_item); + if (!pdu_session_res_modify_response_item_to_asn1(resp_item, cu_cp_resp_item)) { + return false; + } resp->pdu_session_res_modify_list_mod_res.push_back(resp_item); } } @@ -652,10 +676,14 @@ inline void fill_asn1_pdu_session_res_modify_response(asn1::ngap::pdu_session_re resp->pdu_session_res_failed_to_modify_list_mod_res_present = true; for (const auto& cu_cp_resp_item : cu_cp_resp.pdu_session_res_failed_to_modify_list) { asn1::ngap::pdu_session_res_failed_to_modify_item_mod_res_s resp_item; - pdu_session_res_failed_to_modify_item_to_asn1(resp_item, cu_cp_resp_item); + if (!pdu_session_res_failed_to_modify_item_to_asn1(resp_item, cu_cp_resp_item)) { + return false; + } resp->pdu_session_res_failed_to_modify_list_mod_res.push_back(resp_item); } } + + return true; } /// \brief Convert common type UE Context Release Request to NGAP UE Context Release Request. @@ -677,7 +705,7 @@ inline void fill_asn1_ue_context_release_request(asn1::ngap::ue_context_release_ asn1_msg->cause = cause_to_asn1(msg.cause); } -/// \brief Convert NGAP ASN1 PDU Session Resource Release Comman ASN1 struct to common type. +/// \brief Convert NGAP ASN1 PDU Session Resource Release Command ASN1 struct to common type. /// \param[out] pdu_session_resource_release_cmd The cu_cp_pdu_session_resource_release_command struct to fill. /// \param[in] asn1_pdu_session_resource_release_cmd The pdu_session_res_release_cmd ASN1 struct. inline void fill_cu_cp_pdu_session_resource_release_command( @@ -715,9 +743,11 @@ inline void fill_cu_cp_pdu_session_resource_release_command( } /// \brief Convert common type PDU Session Resource Release Response message to NGAP PDU Session Resource Release -/// Response \param[out] resp The ASN1 NGAP PDU Session Resource Release Response message. +/// Response. +/// \param[out] resp The ASN1 NGAP PDU Session Resource Release Response message. /// \param[in] cu_cp_resp The CU-CP PDU Session Resource Release Response message. -inline void +/// \return True on success, otherwise false. +inline bool fill_asn1_pdu_session_resource_release_response(asn1::ngap::pdu_session_res_release_resp_s& resp, const cu_cp_pdu_session_resource_release_response& cu_cp_resp) { @@ -790,7 +820,9 @@ fill_asn1_pdu_session_resource_release_response(asn1::ngap::pdu_session_res_rele // Pack pdu_session_res_release_resp_transfer_s byte_buffer pdu = pack_into_pdu(res_release_resp_transfer); - asn1_pdu_session_res_released_item.pdu_session_res_release_resp_transfer.resize(pdu.length()); + if (!asn1_pdu_session_res_released_item.pdu_session_res_release_resp_transfer.resize(pdu.length())) { + return false; + } std::copy(pdu.begin(), pdu.end(), asn1_pdu_session_res_released_item.pdu_session_res_release_resp_transfer.begin()); resp->pdu_session_res_released_list_rel_res.push_back(asn1_pdu_session_res_released_item); @@ -801,6 +833,8 @@ fill_asn1_pdu_session_resource_release_response(asn1::ngap::pdu_session_res_rele resp->user_location_info.set_user_location_info_nr() = cu_cp_user_location_info_to_asn1(cu_cp_resp.user_location_info.value()); } + + return true; } /// \brief Convert NGAP ASN1 UE Context Release Command ASN1 struct to common type. @@ -818,7 +852,7 @@ fill_cu_cp_ue_context_release_command(cu_cp_ue_context_release_command& /// \param[out] asn1_resp The ASN1 NGAP UE Context Release Complete message. /// \param[in] cu_cp_resp The CU-CP UE Context Release Complete message. inline void fill_asn1_ue_context_release_complete(asn1::ngap::ue_context_release_complete_s& asn1_resp, - const cu_cp_ue_context_release_complete cu_cp_resp) + const cu_cp_ue_context_release_complete& cu_cp_resp) { // add user location info if (cu_cp_resp.user_location_info.has_value()) { @@ -1084,7 +1118,7 @@ inline bool fill_asn1_handover_resource_allocation_response(asn1::ngap::ho_request_ack_s& asn1_ho_request_ack, const ngap_handover_resource_allocation_response& ho_response) { - if (ho_response.success == true) { + if (ho_response.success) { // pdu session res admitted list for (const auto& admitted_item : ho_response.pdu_session_res_admitted_list) { asn1::ngap::pdu_session_res_admitted_item_s asn1_admitted_item; diff --git a/lib/ngap/ngap_impl.cpp b/lib/ngap/ngap_impl.cpp index 3dc2345e58..afa5e4a048 100644 --- a/lib/ngap/ngap_impl.cpp +++ b/lib/ngap/ngap_impl.cpp @@ -442,11 +442,11 @@ void ngap_impl::handle_pdu_session_resource_modify_request(const asn1::ngap::pdu ue_ctxt.logger.log_warning("Received duplicate PduSessionResourceModifyRequest"); schedule_error_indication(ue_ctxt.ue_ids.ue_index, cause_radio_network_t::unspecified); return; - } else { - // Store last PDU session resource modify request - ue_ctxt.last_pdu_session_resource_modify_request = asn1_request_pdu.copy(); } + // Store last PDU session resource modify request + ue_ctxt.last_pdu_session_resource_modify_request = asn1_request_pdu.copy(); + ngap_ue* ue = ue_manager.find_ngap_ue(ue_ctxt.ue_ids.ue_index); srsran_assert(ue != nullptr, "ue={} ran_ue_id={} amf_ue_id={}: UE for UE context doesn't exist", @@ -463,7 +463,11 @@ void ngap_impl::handle_pdu_session_resource_modify_request(const asn1::ngap::pdu // Convert to common type cu_cp_pdu_session_resource_modify_request msg; msg.ue_index = ue_ctxt.ue_ids.ue_index; - fill_cu_cp_pdu_session_resource_modify_request(msg, request->pdu_session_res_modify_list_mod_req); + if (!fill_cu_cp_pdu_session_resource_modify_request(msg, request->pdu_session_res_modify_list_mod_req)) { + ue_ctxt.logger.log_warning("Unable to fill ASN1 contents for PduSessionResourceModifyRequest"); + schedule_error_indication(ue_ctxt.ue_ids.ue_index, cause_radio_network_t::unspecified); + return; + } // start routine task_sched.schedule_async_task( @@ -507,7 +511,11 @@ void ngap_impl::handle_pdu_session_resource_release_command(const asn1::ngap::pd // Handle optional NAS PDU if (command->nas_pdu_present) { byte_buffer nas_pdu; - nas_pdu.resize(command->nas_pdu.size()); + if (!nas_pdu.resize(command->nas_pdu.size())) { + ue_ctxt.logger.log_warning("Unable to resize the storage for the PduSessionResourceReleaseCommand PDU"); + schedule_error_indication(ue_ctxt.ue_ids.ue_index, cause_radio_network_t::unspecified); + return; + } std::copy(command->nas_pdu.begin(), command->nas_pdu.end(), nas_pdu.begin()); ue_ctxt.logger.log_debug(nas_pdu.begin(), nas_pdu.end(), "DlNasTransport PDU ({} B)", nas_pdu.length()); @@ -553,10 +561,10 @@ void ngap_impl::handle_ue_context_release_command(const asn1::ngap::ue_context_r ue_ctxt.logger.log_info("Dropping UeContextReleaseCommand. UE is already scheduled for release"); schedule_error_indication(ue_ctxt.ue_ids.ue_index, cause_radio_network_t::unknown_local_ue_ngap_id, amf_ue_id); return; - } else { - ue_ctxt.release_scheduled = true; } + ue_ctxt.release_scheduled = true; + if (ran_ue_id == ran_ue_id_t::invalid) { ran_ue_id = ue_ctxt.ue_ids.ran_ue_id; } @@ -592,7 +600,7 @@ void ngap_impl::handle_paging(const asn1::ngap::paging_s& msg) logger.info("Received Paging"); if (msg->ue_paging_id.type() != asn1::ngap::ue_paging_id_c::types::five_g_s_tmsi) { - logger.warning("Dropping PDU. Unsupportet UE Paging ID"); + logger.warning("Dropping PDU. Unsupported UE Paging ID"); send_error_indication(ngap_notifier, logger); return; } @@ -661,7 +669,7 @@ void ngap_impl::handle_error_indication(const asn1::ngap::error_ind_s& msg) amf_ue_id_t amf_ue_id = amf_ue_id_t::invalid; ran_ue_id_t ran_ue_id = ran_ue_id_t::invalid; ue_index_t ue_index = ue_index_t::invalid; - std::string msg_cause = ""; + std::string msg_cause; if (msg->cause_present) { msg_cause = asn1_cause_to_string(msg->cause); diff --git a/lib/ngap/procedures/ngap_initial_context_setup_procedure.cpp b/lib/ngap/procedures/ngap_initial_context_setup_procedure.cpp index 2f37514a71..d8358bcd57 100644 --- a/lib/ngap/procedures/ngap_initial_context_setup_procedure.cpp +++ b/lib/ngap/procedures/ngap_initial_context_setup_procedure.cpp @@ -121,7 +121,10 @@ void ngap_initial_context_setup_procedure::send_initial_context_setup_response( init_ctxt_setup_resp->amf_ue_ngap_id = amf_ue_id_to_uint(amf_ue_id); init_ctxt_setup_resp->ran_ue_ngap_id = ran_ue_id_to_uint(ran_ue_id); - fill_asn1_initial_context_setup_response(init_ctxt_setup_resp, msg); + if (!fill_asn1_initial_context_setup_response(init_ctxt_setup_resp, msg)) { + logger.log_warning("Unable to fill ASN1 contents for InitialContextSetupResponse"); + return; + } logger.log_info("Sending InitialContextSetupResponse"); amf_notifier.on_new_message(ngap_msg); diff --git a/lib/ngap/procedures/ngap_pdu_session_resource_modify_procedure.cpp b/lib/ngap/procedures/ngap_pdu_session_resource_modify_procedure.cpp index 4172d19f28..c9ef1d2b5f 100644 --- a/lib/ngap/procedures/ngap_pdu_session_resource_modify_procedure.cpp +++ b/lib/ngap/procedures/ngap_pdu_session_resource_modify_procedure.cpp @@ -97,7 +97,11 @@ void ngap_pdu_session_resource_modify_procedure::send_pdu_session_resource_modif pdu_session_res_modify_resp->amf_ue_ngap_id = amf_ue_id_to_uint(ue_ids.amf_ue_id); pdu_session_res_modify_resp->ran_ue_ngap_id = ran_ue_id_to_uint(ue_ids.ran_ue_id); - fill_asn1_pdu_session_res_modify_response(pdu_session_res_modify_resp, response); + // TODO: needs more handling in the coro above? + if (!fill_asn1_pdu_session_res_modify_response(pdu_session_res_modify_resp, response)) { + logger.log_warning("Unable to fill ASN1 contents of PDUSessionResourceModifyResponse", name()); + return; + } logger.log_info("Sending PduSessionResourceModifyResponse"); amf_notifier.on_new_message(ngap_msg); diff --git a/lib/ngap/procedures/ngap_pdu_session_resource_release_procedure.cpp b/lib/ngap/procedures/ngap_pdu_session_resource_release_procedure.cpp index 216a65ebc0..520545a4bf 100644 --- a/lib/ngap/procedures/ngap_pdu_session_resource_release_procedure.cpp +++ b/lib/ngap/procedures/ngap_pdu_session_resource_release_procedure.cpp @@ -56,8 +56,12 @@ void ngap_pdu_session_resource_release_procedure::send_pdu_session_resource_rele ngap_msg.pdu.set_successful_outcome(); ngap_msg.pdu.successful_outcome().load_info_obj(ASN1_NGAP_ID_PDU_SESSION_RES_RELEASE); - fill_asn1_pdu_session_resource_release_response( - ngap_msg.pdu.successful_outcome().value.pdu_session_res_release_resp(), response); + // TODO: needs more handling in the coro above? + if (!fill_asn1_pdu_session_resource_release_response( + ngap_msg.pdu.successful_outcome().value.pdu_session_res_release_resp(), response)) { + logger.log_warning("Cannot fill ASN1 PDU Session Resource Release Response"); + return; + } auto& pdu_session_res_release_resp = ngap_msg.pdu.successful_outcome().value.pdu_session_res_release_resp(); pdu_session_res_release_resp->amf_ue_ngap_id = amf_ue_id_to_uint(ue_ids.amf_ue_id); diff --git a/lib/rlc/rlc_rx_am_entity.cpp b/lib/rlc/rlc_rx_am_entity.cpp index b83ab0e8d1..ab951b17e5 100644 --- a/lib/rlc/rlc_rx_am_entity.cpp +++ b/lib/rlc/rlc_rx_am_entity.cpp @@ -358,7 +358,11 @@ bool rlc_rx_am_entity::handle_segment_data_sdu(const rlc_am_pdu_header& header, // Assemble SDU from segments for (const rlc_rx_am_sdu_segment& segm : rx_sdu.segments) { logger.log_debug("Chaining segment. so={} len={}", segm.so, segm.payload.length()); - rx_sdu.sdu.append(segm.payload.copy()); + if (not rx_sdu.sdu.append(segm.payload.copy())) { + logger.log_error("Unable to append segment in byte_buffer_chain"); + // Drop SDU if any of the segments failed to be appended. + return false; + } } rx_sdu.segments.clear(); logger.log_debug("Assembled SDU from segments. sn={} sdu_len={}", header.sn, rx_sdu.sdu.length()); diff --git a/lib/rlc/rlc_rx_um_entity.cpp b/lib/rlc/rlc_rx_um_entity.cpp index 7ba166dbd5..869c5cec4e 100644 --- a/lib/rlc/rlc_rx_um_entity.cpp +++ b/lib/rlc/rlc_rx_um_entity.cpp @@ -274,7 +274,11 @@ bool rlc_rx_um_entity::handle_segment_data_sdu(const rlc_um_pdu_header& header, // Assemble SDU from segments for (const rlc_rx_um_sdu_segment& segm : rx_sdu.segments) { logger.log_debug("Chaining segment. so={} len={}", segm.so, segm.payload.length()); - rx_sdu.sdu.append(segm.payload.copy()); + if (not rx_sdu.sdu.append(segm.payload.copy())) { + logger.log_error("Unable to append segment in byte_buffer_chain"); + // Drop SDU if any of the segments failed to be appended. + return false; + } } rx_sdu.segments.clear(); logger.log_debug("Assembled SDU from segments. sn={} sdu_len={}", header.sn, rx_sdu.sdu.length()); diff --git a/lib/rrc/ue/procedures/rrc_setup_procedure.cpp b/lib/rrc/ue/procedures/rrc_setup_procedure.cpp index 87f0e3ecb3..1b410e5f6c 100644 --- a/lib/rrc/ue/procedures/rrc_setup_procedure.cpp +++ b/lib/rrc/ue/procedures/rrc_setup_procedure.cpp @@ -79,7 +79,10 @@ void rrc_setup_procedure::send_rrc_setup() dl_ccch_msg_s dl_ccch_msg; dl_ccch_msg.msg.set_c1().set_rrc_setup(); rrc_setup_s& rrc_setup = dl_ccch_msg.msg.c1().rrc_setup(); - fill_asn1_rrc_setup_msg(rrc_setup, du_to_cu_container, transaction.id()); + if (!fill_asn1_rrc_setup_msg(rrc_setup, du_to_cu_container, transaction.id())) { + logger.log_warning("ASN1 RRC setup message fill failed"); + return; + } rrc_ue.on_new_dl_ccch(dl_ccch_msg); } diff --git a/lib/rrc/ue/rrc_asn1_helpers.h b/lib/rrc/ue/rrc_asn1_helpers.h index b8c278d29c..dc749ec0b3 100644 --- a/lib/rrc/ue/rrc_asn1_helpers.h +++ b/lib/rrc/ue/rrc_asn1_helpers.h @@ -22,7 +22,8 @@ namespace srs_cu_cp { /// \brief Fills ASN.1 RRC Setup struct. /// \param[out] rrc_setup The RRC Setup ASN.1 struct to fill. /// \param[in] init_ul_rrc_transfer_msg The Init_UL_RRC_Transfer message received by the CU. -inline void +/// \return True on success, otherwise false. +inline bool fill_asn1_rrc_setup_msg(asn1::rrc_nr::rrc_setup_s& rrc_setup, const byte_buffer& mcg, uint8_t rrc_transaction_id) { using namespace asn1::rrc_nr; @@ -37,8 +38,12 @@ fill_asn1_rrc_setup_msg(asn1::rrc_nr::rrc_setup_s& rrc_setup, const byte_buffer& // Copy cell config from DU_to_CU_RRC_Container to master cell group auto& master_cell_group = setup_ies.master_cell_group; - master_cell_group.resize(mcg.length()); + if (!master_cell_group.resize(mcg.length())) { + return false; + } + std::copy(mcg.begin(), mcg.end(), master_cell_group.begin()); + return true; } /// Extracts transaction id of RRC Setup complete message. diff --git a/lib/support/byte_buffer.cpp b/lib/support/byte_buffer.cpp index f21eed2338..7c9d8de80c 100644 --- a/lib/support/byte_buffer.cpp +++ b/lib/support/byte_buffer.cpp @@ -22,7 +22,7 @@ size_t srsran::byte_buffer_segment_pool_default_segment_size() detail::byte_buffer_segment_pool& srsran::detail::get_default_byte_buffer_segment_pool() { // Initialize byte buffer segment pool, if not yet initialized. - // Note: In case of unit tests, this function will be called rather than init_byte_buffer_segment_pool(...) + // Note: In case of unit tests, this function will be called rather than init_byte_buffer_segment_pool(...). constexpr static size_t default_byte_buffer_segment_pool_size = 16384; static auto& pool = detail::byte_buffer_segment_pool::get_instance(default_byte_buffer_segment_pool_size, byte_buffer_segment_pool_default_segment_size()); @@ -75,7 +75,7 @@ struct control_block_allocator { template struct rebind { - typedef control_block_allocator other; + using other = control_block_allocator; }; control_block_allocator(memory_arena_linear_allocator& arena_) noexcept : arena(&arena_), mem_block(arena->mem_block) @@ -180,7 +180,7 @@ bool byte_buffer::append(const byte_buffer& other) return false; } for (node_t* seg = other.ctrl_blk_ptr->segments.head; seg != nullptr; seg = seg->next) { - auto other_it = seg->begin(); + auto* other_it = seg->begin(); while (other_it != seg->end()) { if (ctrl_blk_ptr->segments.tail->tailroom() == 0 and not append_segment(0)) { return false; @@ -262,9 +262,9 @@ byte_buffer::node_t* byte_buffer::create_head_segment(size_t headroom) // For first segment of byte_buffer, add a headroom. void* segment_start = arena.allocate(sizeof(node_t), alignof(node_t)); srsran_assert(block_size > arena.offset, "The memory block provided by the pool is too small"); - size_t segment_size = block_size - arena.offset; - void* payload_start = arena.allocate(segment_size, 1); - node_t* node = new (segment_start) + size_t segment_size = block_size - arena.offset; + void* payload_start = arena.allocate(segment_size, 1); + auto* node = new (segment_start) node_t(span{static_cast(payload_start), segment_size}, std::min(headroom, segment_size)); // Register segment as sharing the same memory block with control block. @@ -377,8 +377,7 @@ bool byte_buffer::prepend(byte_buffer&& other) } if (not other.ctrl_blk_ptr.unique()) { // Deep copy of segments. - prepend(other); - return true; + return prepend(other); } // This is the last reference to "other". Shallow copy, except control segment. diff --git a/tests/benchmarks/du_high/du_high_benchmark.cpp b/tests/benchmarks/du_high/du_high_benchmark.cpp index 13b5b9a8d2..3ebfce741a 100644 --- a/tests/benchmarks/du_high/du_high_benchmark.cpp +++ b/tests/benchmarks/du_high/du_high_benchmark.cpp @@ -734,7 +734,10 @@ class du_high_bench } if (i == nof_dl_pdus_per_slot - 1 and last_dl_pdu_size != 0) { // If it is last DL PDU. - pdu_copy.resize(last_dl_pdu_size); + if (!pdu_copy.resize(last_dl_pdu_size)) { + test_logger.warning("Unable to resize PDU to {} bytes", last_dl_pdu_size); + return; + } } du_notif->on_new_sdu(pdcp_tx_pdu{.buf = std::move(pdu_copy), .pdcp_sn = pdcp_sn_list[bearer_idx]}); } diff --git a/tests/unittests/adt/byte_buffer_chain_test.cpp b/tests/unittests/adt/byte_buffer_chain_test.cpp index dbff9346ce..07f58283a5 100644 --- a/tests/unittests/adt/byte_buffer_chain_test.cpp +++ b/tests/unittests/adt/byte_buffer_chain_test.cpp @@ -52,11 +52,11 @@ TEST_F(byte_buffer_chain_test, empty_container_in_valid_state) ASSERT_EQ(chain.length(), 0U); ASSERT_EQ(chain.begin(), chain.end()); - chain.append(byte_buffer{}); + ASSERT_TRUE(chain.append(byte_buffer{})); ASSERT_EQ(chain.length(), 0U); ASSERT_EQ(chain.begin(), chain.end()); - chain.prepend(byte_buffer{}); + ASSERT_TRUE(chain.prepend(byte_buffer{})); ASSERT_EQ(chain.length(), 0U); ASSERT_EQ(chain.begin(), chain.end()); ASSERT_TRUE(chain.slices().empty()); @@ -70,8 +70,8 @@ TEST_F(byte_buffer_chain_test, append_byte_buffer) byte_buffer other_buffer2{6, 7, 8}; byte_buffer buf_concat = other_buffer.deep_copy(); ASSERT_TRUE(buf_concat.append(other_buffer2.deep_copy())); - buf.append(other_buffer.copy()); - buf.append(other_buffer2.copy()); + ASSERT_TRUE(buf.append(other_buffer.copy())); + ASSERT_TRUE(buf.append(other_buffer2.copy())); // Test length/empty methods. ASSERT_FALSE(buf.empty()); @@ -109,7 +109,7 @@ TEST_F(byte_buffer_chain_test, prepend_buffer) ASSERT_TRUE(buf.empty()); // Set header using a span of bytes. - buf.prepend(buf2.deep_copy()); + ASSERT_TRUE(buf.prepend(buf2.deep_copy())); ASSERT_FALSE(buf.empty()); ASSERT_EQ(3, buf.length()); ASSERT_EQ(buf, vec); @@ -125,14 +125,14 @@ TEST_F(byte_buffer_chain_test, prepend_buffer) // Set header avoiding ref-count increment and avoiding deep copy. buf.clear(); - buf.prepend(std::move(buf2)); + ASSERT_TRUE(buf.prepend(std::move(buf2))); ASSERT_EQ(buf, vec); ASSERT_TRUE(buf2.empty()); // Set header by ref-count increment, avoiding deep copy. buf.clear(); buf2 = vec; - buf.prepend(buf2.copy()); + ASSERT_TRUE(buf.prepend(buf2.copy())); ASSERT_EQ(buf, vec); *buf2.begin() = 5; ASSERT_NE(buf, vec); @@ -140,7 +140,7 @@ TEST_F(byte_buffer_chain_test, prepend_buffer) // Set header by deep copy. buf.clear(); buf2 = vec; - buf.prepend(buf2.deep_copy()); + ASSERT_TRUE(buf.prepend(buf2.deep_copy())); ASSERT_EQ(buf, vec); *buf2.begin() = 5; ASSERT_EQ(buf, vec); @@ -153,9 +153,9 @@ TEST_F(byte_buffer_chain_test, prepend_header_and_append_payload) byte_buffer header_bytes = {1, 2, 3}; byte_buffer payload = {4, 5, 6}; - buf.prepend(header_bytes.deep_copy()); + ASSERT_TRUE(buf.prepend(header_bytes.deep_copy())); ASSERT_EQ(header_bytes.length(), buf.length()); - buf.append(payload.copy()); + ASSERT_TRUE(buf.append(payload.copy())); ASSERT_EQ(header_bytes.length() + payload.length(), buf.length()); // Test comparison. @@ -192,9 +192,9 @@ TEST_F(byte_buffer_chain_test, payload_lifetime) all_bytes.insert(all_bytes.end(), payload1.begin(), payload1.end()); all_bytes.insert(all_bytes.end(), payload2.begin(), payload2.end()); - buf.prepend(header_bytes.copy()); - buf.append(std::move(payload1)); - buf.append(payload2.copy()); + ASSERT_TRUE(buf.prepend(header_bytes.copy())); + ASSERT_TRUE(buf.append(std::move(payload1))); + ASSERT_TRUE(buf.append(payload2.copy())); } // Note: header and payload went out of scope, but that shouldnt affect the rlc buffer content. @@ -209,8 +209,8 @@ TEST_F(byte_buffer_chain_test, slice_chain_formatter) ASSERT_TRUE(pdu2.append(bytes)); byte_buffer_chain chain; - chain.append(byte_buffer_slice{std::move(pdu), 3, 2}); - chain.append(byte_buffer_slice{std::move(pdu2), 0, 2}); + ASSERT_TRUE(chain.append(byte_buffer_slice{std::move(pdu), 3, 2})); + ASSERT_TRUE(chain.append(byte_buffer_slice{std::move(pdu2), 0, 2})); for (auto& b : chain) { ASSERT_TRUE(b > 0); diff --git a/tests/unittests/adt/byte_buffer_test.cpp b/tests/unittests/adt/byte_buffer_test.cpp index bcea207706..9490113c1d 100644 --- a/tests/unittests/adt/byte_buffer_test.cpp +++ b/tests/unittests/adt/byte_buffer_test.cpp @@ -168,7 +168,7 @@ TEST_F(byte_buffer_tester, empty_byte_buffer_in_valid_state) ASSERT_EQ(pdu, std::list{}) << "Comparison with empty non-span type failed"; ASSERT_EQ(pdu.segments().begin(), pdu.segments().end()); ASSERT_TRUE(pdu.is_contiguous()); - pdu.resize(0); + ASSERT_TRUE(pdu.resize(0)); ASSERT_EQ_LEN(pdu, 0); pdu.clear(); ASSERT_EQ_LEN(pdu, 0); @@ -277,12 +277,12 @@ TEST_P(two_vector_size_param_test, prepend) byte_buffer pdu; // prepend in empty byte_buffer. - pdu.prepend(bytes1); + ASSERT_TRUE(pdu.prepend(bytes1)); ASSERT_EQ(pdu.length(), bytes1.size()); ASSERT_EQ(pdu, bytes1); // prepend in non-empty byte_buffer. - pdu.prepend(bytes2); + ASSERT_TRUE(pdu.prepend(bytes2)); ASSERT_EQ(pdu.length(), bytes1.size() + bytes2.size()); ASSERT_EQ(pdu, concat_vec(bytes2, bytes1)); } @@ -408,7 +408,7 @@ TEST_P(three_vector_size_param_test, shallow_copy_prepend_and_append) byte_buffer pdu2 = pdu.copy(); ASSERT_EQ_BUFFER(pdu2, pdu); ASSERT_EQ_BUFFER(pdu2, bytes1); - pdu2.prepend(bytes2); + ASSERT_TRUE(pdu2.prepend(bytes2)); ASSERT_EQ(pdu2, pdu); ASSERT_TRUE(pdu2.append(bytes3)); ASSERT_EQ(pdu2, pdu); @@ -468,7 +468,7 @@ TEST_F(byte_buffer_tester, prepend_and_trim_tail) ASSERT_TRUE(sdu.append(pdu.begin() + prefix_len, pdu.end())); std::array hdr_buf; std::copy(pdu.begin(), pdu.begin() + prefix_len, hdr_buf.begin()); - sdu.prepend(hdr_buf); + ASSERT_TRUE(sdu.prepend(hdr_buf)); ASSERT_EQ(sdu.length(), pdu_len); ASSERT_EQ(std::distance(sdu.begin(), sdu.end()), pdu_len); @@ -485,7 +485,7 @@ TEST_P(three_vector_size_param_test, shallow_copy_prepend_and_append_keeps_valid byte_buffer pdu{bytes1}; byte_buffer pdu2{pdu.copy()}; - pdu.prepend(bytes2); + ASSERT_TRUE(pdu.prepend(bytes2)); ASSERT_TRUE(pdu.append(bytes3)); ASSERT_EQ(pdu, concat_vec(concat_vec(bytes2, bytes1), bytes3)); @@ -760,14 +760,14 @@ TEST_F(byte_buffer_tester, append_rvalue_byte_buffer) // Chain small vector to empty buffer byte_buffer pdu2(small_vec); ASSERT_EQ(pdu2, small_vec); - pdu.prepend(std::move(pdu2)); + ASSERT_TRUE(pdu.prepend(std::move(pdu2))); ASSERT_FALSE(pdu.empty()); ASSERT_EQ(pdu, small_vec); ASSERT_TRUE(pdu2.empty()); // Chain byte_buffer before another non-empty byte_buffer. ASSERT_TRUE(pdu2.append(big_vec)); - pdu.prepend(std::move(pdu2)); + ASSERT_TRUE(pdu.prepend(std::move(pdu2))); ASSERT_TRUE(pdu2.empty()); ASSERT_EQ_LEN(pdu, big_vec.size() + small_vec.size()); ASSERT_EQ(pdu, bytes_concat); diff --git a/tests/unittests/cu_cp/du_processor_test_messages.cpp b/tests/unittests/cu_cp/du_processor_test_messages.cpp index 880cbf2bc5..2554175ab6 100644 --- a/tests/unittests/cu_cp/du_processor_test_messages.cpp +++ b/tests/unittests/cu_cp/du_processor_test_messages.cpp @@ -114,7 +114,8 @@ srsran::srs_cu_cp::generate_pdu_session_resource_setup(unsigned num_pdu_sessions cu_cp_pdu_session_res_setup_item item; item.pdu_session_id = pdu_session_id; - item.pdu_session_nas_pdu.resize(2); + bool ret = item.pdu_session_nas_pdu.resize(2); + (void)ret; item.pdu_session_nas_pdu[0] = 0xaa; item.pdu_session_nas_pdu[1] = 0xbb; item.s_nssai.sst = 1; diff --git a/tests/unittests/e2/common/e2_test_helpers.h b/tests/unittests/e2/common/e2_test_helpers.h index 851a76fc41..6c97d2646e 100644 --- a/tests/unittests/e2/common/e2_test_helpers.h +++ b/tests/unittests/e2/common/e2_test_helpers.h @@ -171,7 +171,8 @@ inline e2_message generate_ric_control_request_style2_action6(srslog::basic_logg logger.error("Failed to pack E2SM RC control header\n"); } - ric_control_request->ri_cctrl_hdr.value.resize(ctrl_hdr_buff.length()); + bool ret = ric_control_request->ri_cctrl_hdr.value.resize(ctrl_hdr_buff.length()); + (void)ret; std::copy(ctrl_hdr_buff.begin(), ctrl_hdr_buff.end(), ric_control_request->ri_cctrl_hdr.value.begin()); asn1::e2sm_rc::e2_sm_rc_ctrl_msg_s ctrl_msg; @@ -202,7 +203,8 @@ inline e2_message generate_ric_control_request_style2_action6(srslog::basic_logg logger.error("Failed to pack E2SM RC control message\n"); } - ric_control_request->ri_cctrl_msg.value.resize(ctrl_msg_buff.length()); + ret = ric_control_request->ri_cctrl_msg.value.resize(ctrl_msg_buff.length()); + (void)ret; std::copy(ctrl_msg_buff.begin(), ctrl_msg_buff.end(), ric_control_request->ri_cctrl_msg.value.begin()); return e2_msg; } @@ -241,7 +243,8 @@ inline e2_message generate_ric_control_request(srslog::basic_logger& logger, logger.error("Failed to pack E2SM RC control header\n"); } - ric_control_request->ri_cctrl_hdr.value.resize(ctrl_hdr_buff.length()); + bool ret = ric_control_request->ri_cctrl_hdr.value.resize(ctrl_hdr_buff.length()); + (void)ret; std::copy(ctrl_hdr_buff.begin(), ctrl_hdr_buff.end(), ric_control_request->ri_cctrl_hdr.value.begin()); asn1::e2sm_rc::e2_sm_rc_ctrl_msg_s ctrl_msg; @@ -265,7 +268,8 @@ inline e2_message generate_ric_control_request(srslog::basic_logger& logger, logger.error("Failed to pack E2SM RC control message\n"); } - ric_control_request->ri_cctrl_msg.value.resize(ctrl_msg_buff.length()); + ret = ric_control_request->ri_cctrl_msg.value.resize(ctrl_msg_buff.length()); + (void)ret; std::copy(ctrl_msg_buff.begin(), ctrl_msg_buff.end(), ric_control_request->ri_cctrl_msg.value.begin()); return e2_msg; } @@ -601,7 +605,8 @@ inline asn1::e2ap::ri_caction_to_be_setup_item_s generate_e2sm_kpm_ric_action(e2 return {}; } - ric_action.ric_action_definition.resize(buf.length()); + bool ret = ric_action.ric_action_definition.resize(buf.length()); + (void)ret; std::copy(buf.begin(), buf.end(), ric_action.ric_action_definition.begin()); return ric_action; } @@ -624,7 +629,8 @@ inline e2_message generate_e2sm_kpm_subscription_request(asn1::e2ap::ri_caction_ return {}; } - ric_subscript_reqs->ricsubscription_details->ric_event_trigger_definition.resize(buf.length()); + bool ret = ric_subscript_reqs->ricsubscription_details->ric_event_trigger_definition.resize(buf.length()); + (void)ret; std::copy(buf.begin(), buf.end(), ric_subscript_reqs->ricsubscription_details->ric_event_trigger_definition.begin()); e2_message e2_msg; @@ -650,9 +656,11 @@ inline e2_message generate_e2_ind_msg(byte_buffer& ind_hdr_bytes, byte_buffer& i e2_ind.indication->ri_ccall_process_id_present = false; // put RIC indication content into message - e2_ind.indication->ri_cind_msg.value.resize(ind_msg_bytes.length()); + bool ret = e2_ind.indication->ri_cind_msg.value.resize(ind_msg_bytes.length()); + (void)ret; std::copy(ind_msg_bytes.begin(), ind_msg_bytes.end(), e2_ind.indication->ri_cind_msg.value.begin()); - e2_ind.indication->ri_cind_hdr.value.resize(ind_hdr_bytes.length()); + ret = e2_ind.indication->ri_cind_hdr.value.resize(ind_hdr_bytes.length()); + (void)ret; std::copy(ind_hdr_bytes.begin(), ind_hdr_bytes.end(), e2_ind.indication->ri_cind_hdr.value.begin()); e2_message e2_msg; diff --git a/tests/unittests/ngap/ngap_test_messages.cpp b/tests/unittests/ngap/ngap_test_messages.cpp index 73ca08757e..424441458b 100644 --- a/tests/unittests/ngap/ngap_test_messages.cpp +++ b/tests/unittests/ngap/ngap_test_messages.cpp @@ -147,7 +147,8 @@ cu_cp_initial_ue_message srsran::srs_cu_cp::generate_initial_ue_message(ue_index { cu_cp_initial_ue_message msg = {}; msg.ue_index = ue_index; - msg.nas_pdu.resize(nas_pdu_len); + bool ret = msg.nas_pdu.resize(nas_pdu_len); + (void)ret; msg.establishment_cause = static_cast(rrc_establishment_cause_opts::mo_sig); msg.user_location_info.nr_cgi.plmn_hex = "00f110"; msg.user_location_info.nr_cgi.nci = 6576; @@ -169,7 +170,8 @@ ngap_message srsran::srs_cu_cp::generate_downlink_nas_transport_message(amf_ue_i dl_nas_transport_msg->amf_ue_ngap_id = amf_ue_id_to_uint(amf_ue_id); dl_nas_transport_msg->ran_ue_ngap_id = ran_ue_id_to_uint(ran_ue_id); if (nas_pdu.empty()) { - dl_nas_transport_msg->nas_pdu.resize(nas_pdu_len); + bool ret = dl_nas_transport_msg->nas_pdu.resize(nas_pdu_len); + (void)ret; } else { dl_nas_transport_msg->nas_pdu = nas_pdu.copy(); } @@ -181,7 +183,8 @@ cu_cp_ul_nas_transport srsran::srs_cu_cp::generate_ul_nas_transport_message(ue_i { cu_cp_ul_nas_transport ul_nas_transport = {}; ul_nas_transport.ue_index = ue_index; - ul_nas_transport.nas_pdu.resize(nas_pdu_len); + bool ret = ul_nas_transport.nas_pdu.resize(nas_pdu_len); + (void)ret; ul_nas_transport.user_location_info.nr_cgi.plmn_hex = "00f110"; ul_nas_transport.user_location_info.nr_cgi.nci = 6576; ul_nas_transport.user_location_info.tai.plmn_id = "00f110"; @@ -200,7 +203,8 @@ ngap_message srsran::srs_cu_cp::generate_uplink_nas_transport_message(amf_ue_id_ auto& ul_nas_transport_msg = ul_nas_transport.pdu.init_msg().value.ul_nas_transport(); ul_nas_transport_msg->amf_ue_ngap_id = amf_ue_id_to_uint(amf_ue_id); ul_nas_transport_msg->ran_ue_ngap_id = ran_ue_id_to_uint(ran_ue_id); - ul_nas_transport_msg->nas_pdu.resize(nas_pdu_len); + bool ret = ul_nas_transport_msg->nas_pdu.resize(nas_pdu_len); + (void)ret; auto& user_loc_info_nr = ul_nas_transport_msg->user_location_info.set_user_location_info_nr(); user_loc_info_nr.nr_cgi.plmn_id.from_string("00f110"); @@ -869,4 +873,4 @@ ngap_message srsran::srs_cu_cp::generate_valid_handover_command(amf_ue_id_t amf_ ho_cmd->target_to_source_transparent_container = pack_into_pdu(transparent_container); return ngap_msg; -} \ No newline at end of file +} diff --git a/tests/unittests/rlc/rlc_um_test.cpp b/tests/unittests/rlc/rlc_um_test.cpp index 47589ce5cb..48447b62eb 100644 --- a/tests/unittests/rlc/rlc_um_test.cpp +++ b/tests/unittests/rlc/rlc_um_test.cpp @@ -194,7 +194,7 @@ class rlc_um_test : public ::testing::Test, public ::testing::WithParamInterface if (i != hold_back_pdu) { byte_buffer pdu; for (const byte_buffer_slice& slice : pdu_bufs[i].slices()) { - pdu.append(slice); + EXPECT_TRUE(pdu.append(slice)); } rlc2_rx_lower->handle_pdu(std::move(pdu)); } @@ -207,7 +207,7 @@ class rlc_um_test : public ::testing::Test, public ::testing::WithParamInterface { byte_buffer pdu; for (const byte_buffer_slice& slice : pdu_bufs[hold_back_pdu].slices()) { - pdu.append(slice); + EXPECT_TRUE(pdu.append(slice)); } rlc2_rx_lower->handle_pdu(std::move(pdu)); } @@ -364,7 +364,7 @@ TEST_P(rlc_um_test, tx_without_segmentation) for (uint32_t i = 0; i < num_pdus; i++) { byte_buffer pdu; for (const byte_buffer_slice& slice : pdu_bufs[i].slices()) { - pdu.append(slice); + EXPECT_TRUE(pdu.append(slice)); } rlc2_rx_lower->handle_pdu(std::move(pdu)); } @@ -444,7 +444,7 @@ TEST_P(rlc_um_test, tx_with_segmentation) for (uint32_t i = 0; i < num_pdus; i++) { byte_buffer pdu; for (const byte_buffer_slice& slice : pdu_bufs[i].slices()) { - pdu.append(slice); + EXPECT_TRUE(pdu.append(slice)); } rlc2_rx_lower->handle_pdu(std::move(pdu)); } @@ -728,7 +728,7 @@ TEST_P(rlc_um_test, tx_with_segmentation_reverse_rx) for (uint32_t i = 0; i < num_pdus; i++) { byte_buffer pdu; for (const byte_buffer_slice& slice : pdu_bufs[num_pdus - i - 1].slices()) { - pdu.append(slice); + EXPECT_TRUE(pdu.append(slice)); } rlc2_rx_lower->handle_pdu(std::move(pdu)); } @@ -798,7 +798,7 @@ TEST_P(rlc_um_test, tx_multiple_SDUs_with_segmentation) if (i != 1 && i != 6) { byte_buffer pdu; for (const byte_buffer_slice& slice : pdu_bufs[i].slices()) { - pdu.append(slice); + EXPECT_TRUE(pdu.append(slice)); } rlc2_rx_lower->handle_pdu(std::move(pdu)); } @@ -808,14 +808,14 @@ TEST_P(rlc_um_test, tx_multiple_SDUs_with_segmentation) { byte_buffer pdu; for (const byte_buffer_slice& slice : pdu_bufs[6].slices()) { - pdu.append(slice); + EXPECT_TRUE(pdu.append(slice)); } rlc2_rx_lower->handle_pdu(std::move(pdu)); } { byte_buffer pdu; for (const byte_buffer_slice& slice : pdu_bufs[1].slices()) { - pdu.append(slice); + EXPECT_TRUE(pdu.append(slice)); } rlc2_rx_lower->handle_pdu(std::move(pdu)); } @@ -896,7 +896,7 @@ TEST_P(rlc_um_test, reassembly_window_wrap_around) byte_buffer rx_pdu; for (const byte_buffer_slice& slice : tx_pdu.slices()) { - rx_pdu.append(slice); + EXPECT_TRUE(rx_pdu.append(slice)); } rlc2_rx_lower->handle_pdu(std::move(rx_pdu)); @@ -960,7 +960,7 @@ TEST_P(rlc_um_test, lost_PDU_outside_reassembly_window) if (num_pdus != 10 && num_pdus != 21) { byte_buffer rx_pdu; for (const byte_buffer_slice& slice : tx_pdu.slices()) { - rx_pdu.append(slice); + EXPECT_TRUE(rx_pdu.append(slice)); } rlc2_rx_lower->handle_pdu(std::move(rx_pdu)); } else { @@ -1050,7 +1050,7 @@ TEST_P(rlc_um_test, lost_segment_outside_reassembly_window) if (i != 2) { byte_buffer pdu; for (const byte_buffer_slice& slice : pdu_bufs[i].slices()) { - pdu.append(slice); + EXPECT_TRUE(pdu.append(slice)); } rlc2_rx_lower->handle_pdu(std::move(pdu)); } @@ -1136,7 +1136,7 @@ TEST_P(rlc_um_test, out_of_order_segments_across_SDUs) for (uint32_t i = 0; i < num_pdus; i++) { byte_buffer pdu; for (const byte_buffer_slice& slice : pdu_bufs[order[i]].slices()) { - pdu.append(slice); + EXPECT_TRUE(pdu.append(slice)); } rlc2_rx_lower->handle_pdu(std::move(pdu)); } diff --git a/tests/unittests/rrc/rrc_ue_test_helpers.h b/tests/unittests/rrc/rrc_ue_test_helpers.h index 08a1c3cf27..60d4215541 100644 --- a/tests/unittests/rrc/rrc_ue_test_helpers.h +++ b/tests/unittests/rrc/rrc_ue_test_helpers.h @@ -70,7 +70,8 @@ class rrc_ue_test_helper rrc_ue_creation_message rrc_ue_create_msg{}; rrc_ue_create_msg.ue_index = ALLOCATED_UE_INDEX; rrc_ue_create_msg.c_rnti = to_rnti(0x1234); - rrc_ue_create_msg.du_to_cu_container.resize(1); + bool ret = rrc_ue_create_msg.du_to_cu_container.resize(1); + (void)ret; rrc_ue_create_msg.f1ap_pdu_notifier = &rrc_ue_f1ap_notifier; rrc_ue_create_msg.rrc_ue_cu_cp_notifier = &rrc_ue_cu_cp_notifier; rrc_ue_create_msg.measurement_notifier = &rrc_ue_cu_cp_notifier; From 45e813009c4d0719633d84adc0048f1ad9b86f34 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Wed, 21 Feb 2024 13:03:46 +0100 Subject: [PATCH 005/140] sched: fix pusch builder in sch_pdu_builder.cpp Signed-off-by: Carlo Galiotto --- lib/scheduler/support/sch_pdu_builder.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/scheduler/support/sch_pdu_builder.cpp b/lib/scheduler/support/sch_pdu_builder.cpp index 857705c2ab..f1a4b4e321 100644 --- a/lib/scheduler/support/sch_pdu_builder.cpp +++ b/lib/scheduler/support/sch_pdu_builder.cpp @@ -189,9 +189,11 @@ pusch_config_params srsran::get_pusch_config_f0_0_c_rnti(const ue_cell_configura // According to TS 38.214, Section 6.1.4.2, nof_oh_prb is set equal to xOverhead, when set; else nof_oh_prb = 0. // NOTE: x_overhead::not_set is mapped to 0. - pusch.nof_oh_prb = ue_cell_cfg.cfg_dedicated().pdsch_serv_cell_cfg.has_value() - ? static_cast(ue_cell_cfg.cfg_dedicated().pdsch_serv_cell_cfg.value().x_ov_head) - : static_cast(x_overhead::not_set); + pusch.nof_oh_prb = + ue_cell_cfg.cfg_dedicated().ul_config.has_value() and + ue_cell_cfg.cfg_dedicated().ul_config.value().pusch_scell_cfg.has_value() + ? static_cast(ue_cell_cfg.cfg_dedicated().ul_config.value().pusch_scell_cfg.value().x_ov_head) + : static_cast(x_overhead::not_set); // TODO: verify if this needs to be set depending on some configuration. pusch.nof_harq_ack_bits = nof_harq_ack_bits; @@ -251,9 +253,11 @@ pusch_config_params srsran::get_pusch_config_f0_1_c_rnti(const ue_cell_configura // According to TS 38.214, Section 6.1.4.2, nof_oh_prb is set equal to xOverhead, when set; else nof_oh_prb = 0. // NOTE: x_overhead::not_set is mapped to 0. - pusch.nof_oh_prb = ue_cell_cfg.cfg_dedicated().pdsch_serv_cell_cfg.has_value() - ? static_cast(ue_cell_cfg.cfg_dedicated().pdsch_serv_cell_cfg.value().x_ov_head) - : static_cast(x_overhead::not_set); + pusch.nof_oh_prb = + ue_cell_cfg.cfg_dedicated().ul_config.has_value() and + ue_cell_cfg.cfg_dedicated().ul_config.value().pusch_scell_cfg.has_value() + ? static_cast(ue_cell_cfg.cfg_dedicated().ul_config.value().pusch_scell_cfg.value().x_ov_head) + : static_cast(x_overhead::not_set); // TODO: verify if this needs to be set depending on some configuration. pusch.nof_harq_ack_bits = nof_harq_ack_bits; From bbd8d92fb7333158113026bc528d7b0559aeea31 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 19 Feb 2024 17:18:05 +0100 Subject: [PATCH 006/140] ran: add efefctive code rate for DC overlap --- include/srsran/ran/direct_current_offset.h | 31 +++++++++++++++++++ include/srsran/ran/pdsch/dlsch_info.h | 6 +++- include/srsran/ran/pusch/ulsch_info.h | 15 +++++++++ .../pusch/pusch_processor_impl.cpp | 8 +++++ lib/ran/pdsch/dlsch_info.cpp | 9 ++++++ lib/ran/pusch/ulsch_info.cpp | 7 +++++ lib/scheduler/support/mcs_tbs_calculator.cpp | 17 ++++++---- lib/scheduler/support/mcs_tbs_calculator.h | 7 +++-- .../ue_scheduling/ue_cell_grid_allocator.cpp | 13 ++++++-- .../support/mcs_tbs_calculator_test.cpp | 17 +++++----- 10 files changed, 111 insertions(+), 19 deletions(-) diff --git a/include/srsran/ran/direct_current_offset.h b/include/srsran/ran/direct_current_offset.h index b7a346c6e8..a101024659 100644 --- a/include/srsran/ran/direct_current_offset.h +++ b/include/srsran/ran/direct_current_offset.h @@ -12,6 +12,7 @@ #include "resource_block.h" #include "srsran/adt/strong_type.h" +#include "srsran/ran/resource_allocation/rb_interval.h" #include "srsran/support/srsran_assert.h" namespace srsran { @@ -56,6 +57,36 @@ inline uint16_t pack(dc_offset_t offset, unsigned carrier_nof_rbs) return 3300; } +/// \brief Checks if the DC position is contained in a CRB interval. +/// \param[in] offset DC offset parameter. +/// \param[in] carrier_nof_rbs Carrier bandwidth in resource blocks. +/// \param[in] rbs Resource block allocation. +/// \return \c true if the DC position is contained. Otherwise \c false. +inline bool is_contained(dc_offset_t offset, unsigned carrier_nof_rbs, crb_interval rbs) +{ + if (offset == dc_offset_t::undetermined) { + return false; + } + + // Case where DC offset inside spectrum. + const int nof_subcarriers = static_cast(NOF_SUBCARRIERS_PER_RB * carrier_nof_rbs); + auto dc_position = static_cast>(offset); + if (dc_position >= -nof_subcarriers / 2 && dc_position < nof_subcarriers / 2) { + dc_position += nof_subcarriers / 2; + } + + return rbs.contains(dc_position / NOF_SUBCARRIERS_PER_RB); +} + +/// \brief Checks if the DC position is contained in a CRB interval. +/// \param[in] dc_position DC position in subcarriers within the grid relative to PointA. +/// \param[in] rbs Resource block allocation. +/// \return \c true if the DC position is contained. Otherwise \c false. +inline bool is_contained(unsigned dc_position, crb_interval rbs) +{ + return rbs.contains(dc_position / NOF_SUBCARRIERS_PER_RB); +} + } // namespace dc_offset_helper } // namespace srsran diff --git a/include/srsran/ran/pdsch/dlsch_info.h b/include/srsran/ran/pdsch/dlsch_info.h index 1022d48591..e3c8894d2f 100644 --- a/include/srsran/ran/pdsch/dlsch_info.h +++ b/include/srsran/ran/pdsch/dlsch_info.h @@ -40,6 +40,8 @@ struct dlsch_configuration { unsigned nof_cdm_groups_without_data; /// Number of transmission layers. unsigned nof_layers; + /// Set to true if the transmission overlaps with the Direct Current (DC). + bool contains_dc; }; /// Collects Downlink Shared Channel (DL-SCH) derived parameters. @@ -48,6 +50,8 @@ struct dlsch_information { sch_information sch; /// Number of encoded and rate-matched DL-SCH data bits. units::bits nof_dl_sch_bits; + /// Number of bits that are are affected by overlapping with the direct current. + units::bits nof_dc_overlap_bits; /// \brief Calculates the effective code rate normalized between 0 and 1. /// @@ -59,7 +63,7 @@ struct dlsch_information { srsran_assert(sch.nof_bits_per_cb.value() > sch.nof_filler_bits_per_cb.value(), "The number of bits per CB must be greater than the number of filler bits."); return static_cast((sch.nof_bits_per_cb.value() - sch.nof_filler_bits_per_cb.value()) * sch.nof_cb) / - static_cast(nof_dl_sch_bits.value()); + static_cast(nof_dl_sch_bits.value() - nof_dc_overlap_bits.value()); } }; diff --git a/include/srsran/ran/pusch/ulsch_info.h b/include/srsran/ran/pusch/ulsch_info.h index 9cc27bcb52..826a0a7960 100644 --- a/include/srsran/ran/pusch/ulsch_info.h +++ b/include/srsran/ran/pusch/ulsch_info.h @@ -59,6 +59,8 @@ struct ulsch_configuration { unsigned nof_cdm_groups_without_data; /// Number of transmission layers. unsigned nof_layers; + /// Set to true if the transmission overlaps with the Direct Current (DC). + bool contains_dc; }; /// \brief Collects Uplink Shared Channel (UL-SCH) derived parameters. @@ -83,6 +85,8 @@ struct ulsch_information { unsigned nof_csi_part1_re; /// Number of resource elements occupied by CSI Part 1 information. Parameter \f$Q'_\textup{CSI-2}\f$. unsigned nof_csi_part2_re; + /// Number of bits that are are affected by overlapping with the direct current. + units::bits nof_dc_overlap_bits; /// \brief Calculates the effective code rate normalized between 0 and 1. /// @@ -122,6 +126,17 @@ struct ulsch_information { effective_ul_sch_bits -= nof_harq_ack_bits.value(); } + // Adjust the effective rate matched UL-SCH bits considering the bits overlapped with the DC position. + if (nof_dc_overlap_bits > 0_bits) { + // Ensure the subtraction of overlapped DC bits does not result in zero or negative. + srsran_assert(effective_ul_sch_bits > nof_dc_overlap_bits.value(), + "UL-SCH rate match length bits) must be greater than the bits overlapped with DC position ({}).", + effective_ul_sch_bits, + nof_dc_overlap_bits); + + effective_ul_sch_bits -= nof_dc_overlap_bits.value(); + } + // Calculate the exact number of bits to encode, including payload, transport block CRC, and codeblock CRC. unsigned nof_effective_payload_bits = (sch.value().nof_bits_per_cb.value() - sch.value().nof_filler_bits_per_cb.value()) * sch.value().nof_cb; diff --git a/lib/phy/upper/channel_processors/pusch/pusch_processor_impl.cpp b/lib/phy/upper/channel_processors/pusch/pusch_processor_impl.cpp index 80e930fa35..ffe82958ea 100644 --- a/lib/phy/upper/channel_processors/pusch/pusch_processor_impl.cpp +++ b/lib/phy/upper/channel_processors/pusch/pusch_processor_impl.cpp @@ -211,6 +211,13 @@ void pusch_processor_impl::process(span data, // Get RB mask relative to Point A. It assumes PUSCH is never interleaved. bounded_bitset rb_mask = pdu.freq_alloc.get_prb_mask(pdu.bwp_start_rb, pdu.bwp_size_rb); + // Determine if the PUSCH allocation overlaps with the position of the DC. + bool overlap_dc = false; + if (pdu.dc_position.has_value()) { + unsigned dc_position_prb = pdu.dc_position.value() / NRE; + overlap_dc = rb_mask.test(dc_position_prb); + } + // Get UL-SCH information as if there was no CSI Part 2 in the PUSCH. ulsch_configuration ulsch_config; ulsch_config.tbs = units::bytes(data.size()).to_bits(); @@ -229,6 +236,7 @@ void pusch_processor_impl::process(span data, ulsch_config.dmrs_symbol_mask = pdu.dmrs_symbol_mask; ulsch_config.nof_cdm_groups_without_data = pdu.nof_cdm_groups_without_data; ulsch_config.nof_layers = pdu.nof_tx_layers; + ulsch_config.contains_dc = overlap_dc; ulsch_information info = get_ulsch_information(ulsch_config); // Estimate channel. diff --git a/lib/ran/pdsch/dlsch_info.cpp b/lib/ran/pdsch/dlsch_info.cpp index f923191771..cef0cac910 100644 --- a/lib/ran/pdsch/dlsch_info.cpp +++ b/lib/ran/pdsch/dlsch_info.cpp @@ -15,6 +15,8 @@ using namespace srsran; dlsch_information srsran::get_dlsch_information(const dlsch_configuration& config) { + using namespace units::literals; + dlsch_information result = {}; // Get shared channel parameters. @@ -72,5 +74,12 @@ dlsch_information srsran::get_dlsch_information(const dlsch_configuration& confi // Number of bits used for shared channel. result.nof_dl_sch_bits = units::bits(nof_re_dl_sch * config.nof_layers * modulation_order); + // Count the number of rate matched bits that overlap with the DC position. + if (config.contains_dc) { + result.nof_dc_overlap_bits = units::bits(config.nof_symbols * modulation_order); + } else { + result.nof_dc_overlap_bits = 0_bits; + } + return result; } \ No newline at end of file diff --git a/lib/ran/pusch/ulsch_info.cpp b/lib/ran/pusch/ulsch_info.cpp index 9140212c5b..0a85e558e8 100644 --- a/lib/ran/pusch/ulsch_info.cpp +++ b/lib/ran/pusch/ulsch_info.cpp @@ -337,5 +337,12 @@ ulsch_information srsran::get_ulsch_information(const ulsch_configuration& confi // Number of bits used for CSI Part 2. result.nof_csi_part2_bits = units::bits(result.nof_csi_part2_re * config.nof_layers * modulation_order); + // Count the number of rate matched bits that overlap with the DC position. + if (config.contains_dc) { + result.nof_dc_overlap_bits = units::bits(config.nof_symbols * modulation_order); + } else { + result.nof_dc_overlap_bits = 0_bits; + } + return result; } diff --git a/lib/scheduler/support/mcs_tbs_calculator.cpp b/lib/scheduler/support/mcs_tbs_calculator.cpp index 57417009bd..22b05ac273 100644 --- a/lib/scheduler/support/mcs_tbs_calculator.cpp +++ b/lib/scheduler/support/mcs_tbs_calculator.cpp @@ -27,7 +27,8 @@ static ulsch_configuration build_ulsch_info(const pusch_config_params& pusch_c const ue_cell_configuration& ue_cell_cfg, unsigned tbs_bytes, sch_mcs_description mcs_info, - unsigned nof_prbs) + unsigned nof_prbs, + bool contains_dc) { ulsch_configuration ulsch_info{.tbs = static_cast(tbs_bytes * NOF_BITS_PER_BYTE), .mcs_descr = mcs_info, @@ -41,7 +42,8 @@ static ulsch_configuration build_ulsch_info(const pusch_config_params& pusch_c .dmrs_symbol_mask = pusch_cfg.dmrs.dmrs_symb_pos, .nof_cdm_groups_without_data = static_cast(pusch_cfg.dmrs.num_dmrs_cdm_grps_no_data), - .nof_layers = pusch_cfg.nof_layers}; + .nof_layers = pusch_cfg.nof_layers, + .contains_dc = contains_dc}; ulsch_info.alpha_scaling = alpha_scaling_to_float( ue_cell_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pusch_cfg.value().uci_cfg.value().scaling); @@ -150,7 +152,8 @@ static void update_ulsch_info(ulsch_configuration& ulsch_cfg, unsigned tbs_bytes optional srsran::compute_dl_mcs_tbs(const pdsch_config_params& pdsch_params, const ue_cell_configuration& ue_cell_cfg, sch_mcs_index max_mcs, - unsigned nof_prbs) + unsigned nof_prbs, + bool contains_dc) { // The maximum supported code rate is 0.95, as per TS38.214, Section 5.1.3. The maximum code rate is defined for DL, // but we consider the same value for UL. @@ -178,7 +181,8 @@ optional srsran::compute_dl_mcs_tbs(const pdsch_config_params& pd .dmrs_symbol_mask = pdsch_params.dmrs.dmrs_symb_pos, .nof_cdm_groups_without_data = static_cast(pdsch_params.dmrs.num_dmrs_cdm_grps_no_data), - .nof_layers = pdsch_params.nof_layers}; + .nof_layers = pdsch_params.nof_layers, + .contains_dc = contains_dc}; float effective_code_rate = get_dlsch_information(dlsch_info).get_effective_code_rate(); @@ -212,7 +216,8 @@ optional srsran::compute_dl_mcs_tbs(const pdsch_config_params& pd optional srsran::compute_ul_mcs_tbs(const pusch_config_params& pusch_cfg, const ue_cell_configuration& ue_cell_cfg, sch_mcs_index max_mcs, - unsigned nof_prbs) + unsigned nof_prbs, + bool contains_dc) { // The maximum supported code rate is 0.95, as per TS38.214, Section 5.1.3. The maximum code rate is defined for DL, // but we consider the same value for UL. @@ -232,7 +237,7 @@ optional srsran::compute_ul_mcs_tbs(const pusch_config_params& pu NOF_BITS_PER_BYTE; // > Compute the effective code rate. - ulsch_configuration ulsch_cfg = build_ulsch_info(pusch_cfg, ue_cell_cfg, tbs_bytes, mcs_info, nof_prbs); + ulsch_configuration ulsch_cfg = build_ulsch_info(pusch_cfg, ue_cell_cfg, tbs_bytes, mcs_info, nof_prbs, contains_dc); float effective_code_rate = get_ulsch_information(ulsch_cfg).get_effective_code_rate(); // > Decrease the MCS and recompute TBS until the effective code rate is not above the 0.95 threshold. diff --git a/lib/scheduler/support/mcs_tbs_calculator.h b/lib/scheduler/support/mcs_tbs_calculator.h index 53267019a6..25f5486617 100644 --- a/lib/scheduler/support/mcs_tbs_calculator.h +++ b/lib/scheduler/support/mcs_tbs_calculator.h @@ -40,7 +40,8 @@ struct sch_mcs_tbs { optional compute_dl_mcs_tbs(const pdsch_config_params& pdsch_params, const ue_cell_configuration& ue_cell_cfg, sch_mcs_index max_mcs, - unsigned nof_prbs); + unsigned nof_prbs, + bool contains_dc); /// \brief Computes the PUSCH MCS and TBS such that the effective code rate does not exceed 0.95. /// @@ -49,11 +50,13 @@ optional compute_dl_mcs_tbs(const pdsch_config_params& pdsch_para /// \param[in] max_mcs Initial value to be applied for the MCS; the final MCS might be lowered if the effective /// code rate is above 0.95. /// \param[in] nof_prbs Maximum number of PRBs available for the PUSCH transmission. +/// \param[in] contains_dc Set to true if the transmission overlaps with the position of the DC. /// \return The MCS and TBS, if for these values the effective code rate does not exceed 0.95; else, it returns an empty /// optional object. optional compute_ul_mcs_tbs(const pusch_config_params& pusch_params, const ue_cell_configuration& ue_cell_cfg, sch_mcs_index max_mcs, - unsigned nof_prbs); + unsigned nof_prbs, + bool contains_dc); } // namespace srsran diff --git a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp index 9164c95aef..a684ec6b40 100644 --- a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp @@ -272,7 +272,13 @@ alloc_outcome ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& gr optional mcs_tbs_info; // If it's a new Tx, compute the MCS and TBS. if (h_dl.empty()) { - mcs_tbs_info = compute_dl_mcs_tbs(pdsch_cfg, ue_cell_cfg, adjusted_mcs, grant.crbs.length()); + bool contains_dc = false; + if (cell_cfg.dl_cfg_common.freq_info_dl.scs_carrier_list.back().tx_direct_current_location.has_value()) { + contains_dc = dc_offset_helper::is_contained( + cell_cfg.dl_cfg_common.freq_info_dl.scs_carrier_list.back().tx_direct_current_location.value(), grant.crbs); + } + + mcs_tbs_info = compute_dl_mcs_tbs(pdsch_cfg, ue_cell_cfg, adjusted_mcs, grant.crbs.length(), contains_dc); } else { // It is a retx. mcs_tbs_info.emplace( @@ -633,7 +639,10 @@ alloc_outcome ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& gr optional mcs_tbs_info; // If it's a new Tx, compute the MCS and TBS from SNR, payload size, and available RBs. if (h_ul.empty()) { - mcs_tbs_info = compute_ul_mcs_tbs(pusch_cfg, ue_cell_cfg, grant.mcs, grant.crbs.length()); + bool contains_dc = + dc_offset_helper::is_contained(cell_cfg.expert_cfg.ue.initial_ul_dc_offset, cell_cfg.nof_ul_prbs, grant.crbs); + + mcs_tbs_info = compute_ul_mcs_tbs(pusch_cfg, ue_cell_cfg, grant.mcs, grant.crbs.length(), contains_dc); } // If it's a reTx, fetch the MCS and TBS from the previous transmission. else { diff --git a/tests/unittests/scheduler/support/mcs_tbs_calculator_test.cpp b/tests/unittests/scheduler/support/mcs_tbs_calculator_test.cpp index 2c445472aa..12026b3fcc 100644 --- a/tests/unittests/scheduler/support/mcs_tbs_calculator_test.cpp +++ b/tests/unittests/scheduler/support/mcs_tbs_calculator_test.cpp @@ -62,7 +62,7 @@ TEST_P(dl_mcs_tbs_calculator_test_bench, test_values) // Run test function. optional test = - compute_dl_mcs_tbs(pdsch_cfg, ue_cell_cfg, sch_mcs_index(test_entry.max_mcs), test_entry.nof_prbs); + compute_dl_mcs_tbs(pdsch_cfg, ue_cell_cfg, sch_mcs_index(test_entry.max_mcs), test_entry.nof_prbs, false); ASSERT_TRUE(test.has_value()); ASSERT_EQ(GetParam().final_mcs, test.value().mcs); @@ -113,7 +113,7 @@ TEST_P(ul_mcs_tbs_prbs_calculator_test_bench, test_values) // Run test function. optional test = - compute_ul_mcs_tbs(pusch_cfg, ue_cell_cfg, sch_mcs_index(test_entry.max_mcs), test_entry.nof_prbs); + compute_ul_mcs_tbs(pusch_cfg, ue_cell_cfg, sch_mcs_index(test_entry.max_mcs), test_entry.nof_prbs, false); ASSERT_TRUE(test.has_value()); ASSERT_EQ(GetParam().final_mcs, test.value().mcs); @@ -166,7 +166,7 @@ TEST_P(ul_mcs_tbs_prbs_calculator_dci_0_1_test_bench, test_values_with_uci) // Run test function. optional test = - compute_ul_mcs_tbs(pusch_cfg, ue_cell_cfg, sch_mcs_index(test_entry.max_mcs), test_entry.nof_prbs); + compute_ul_mcs_tbs(pusch_cfg, ue_cell_cfg, sch_mcs_index(test_entry.max_mcs), test_entry.nof_prbs, false); ASSERT_TRUE(test.has_value()); ASSERT_EQ(GetParam().final_mcs, test.value().mcs); @@ -223,7 +223,7 @@ TEST_F(ul_mcs_tbs_prbs_calculator_low_mcs_test_bench, test_values_with_uci) // Run test function. optional test = - compute_ul_mcs_tbs(pusch_cfg, ue_cell_cfg, sch_mcs_index(test_1_prb.max_mcs), test_1_prb.nof_prbs); + compute_ul_mcs_tbs(pusch_cfg, ue_cell_cfg, sch_mcs_index(test_1_prb.max_mcs), test_1_prb.nof_prbs, false); ASSERT_TRUE(test.has_value()); ASSERT_EQ(test_1_prb.final_mcs, test.value().mcs); @@ -233,7 +233,7 @@ TEST_F(ul_mcs_tbs_prbs_calculator_low_mcs_test_bench, test_values_with_uci) test_1_prb.max_mcs = 4; // Run test function. - test = compute_ul_mcs_tbs(pusch_cfg, ue_cell_cfg, sch_mcs_index(test_1_prb.max_mcs), test_1_prb.nof_prbs); + test = compute_ul_mcs_tbs(pusch_cfg, ue_cell_cfg, sch_mcs_index(test_1_prb.max_mcs), test_1_prb.nof_prbs, false); ASSERT_FALSE(test.has_value()); @@ -241,7 +241,7 @@ TEST_F(ul_mcs_tbs_prbs_calculator_low_mcs_test_bench, test_values_with_uci) mcs_test_entry test_2_prb{.final_mcs = 4, .tbs_bytes = 19, .max_mcs = 4, .nof_prbs = 2}; // Run test function. - test = compute_ul_mcs_tbs(pusch_cfg, ue_cell_cfg, sch_mcs_index(test_2_prb.max_mcs), test_2_prb.nof_prbs); + test = compute_ul_mcs_tbs(pusch_cfg, ue_cell_cfg, sch_mcs_index(test_2_prb.max_mcs), test_2_prb.nof_prbs, false); ASSERT_TRUE(test.has_value()); ASSERT_EQ(test_2_prb.final_mcs, test.value().mcs); ASSERT_EQ(test_2_prb.tbs_bytes, test.value().tbs); @@ -250,7 +250,8 @@ TEST_F(ul_mcs_tbs_prbs_calculator_low_mcs_test_bench, test_values_with_uci) mcs_test_entry test_2_prb_mcs_0{.final_mcs = 0, .tbs_bytes = 7, .max_mcs = 0, .nof_prbs = 2}; // Run test function. - test = compute_ul_mcs_tbs(pusch_cfg, ue_cell_cfg, sch_mcs_index(test_2_prb_mcs_0.max_mcs), test_2_prb_mcs_0.nof_prbs); + test = compute_ul_mcs_tbs( + pusch_cfg, ue_cell_cfg, sch_mcs_index(test_2_prb_mcs_0.max_mcs), test_2_prb_mcs_0.nof_prbs, false); ASSERT_TRUE(test.has_value()); ASSERT_EQ(test_2_prb_mcs_0.final_mcs, test.value().mcs); ASSERT_EQ(test_2_prb_mcs_0.tbs_bytes, test.value().tbs); @@ -286,7 +287,7 @@ TEST_F(ul_mcs_tbs_prbs_calculator_with_harq_ack, test_values_with_2_harq_bits) // Run test function. optional test = - compute_ul_mcs_tbs(pusch_cfg, ue_cell_cfg, sch_mcs_index(test_1_prb.max_mcs), test_1_prb.nof_prbs); + compute_ul_mcs_tbs(pusch_cfg, ue_cell_cfg, sch_mcs_index(test_1_prb.max_mcs), test_1_prb.nof_prbs, false); ASSERT_TRUE(test.has_value()); ASSERT_EQ(test_1_prb.final_mcs, test.value().mcs); From 2e63e42edbb29731a510356f112fab7722cbfe4a Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 19 Feb 2024 17:22:23 +0100 Subject: [PATCH 007/140] phy: fix mising attribute --- lib/scheduler/support/mcs_tbs_calculator.cpp | 7 ++++--- .../phy/upper/channel_processors/pxsch_chain_test.cpp | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/scheduler/support/mcs_tbs_calculator.cpp b/lib/scheduler/support/mcs_tbs_calculator.cpp index 22b05ac273..2a9a259819 100644 --- a/lib/scheduler/support/mcs_tbs_calculator.cpp +++ b/lib/scheduler/support/mcs_tbs_calculator.cpp @@ -199,9 +199,10 @@ optional srsran::compute_dl_mcs_tbs(const pdsch_config_params& pd .tb_scaling_field = pdsch_params.tb_scaling_field, .n_prb = nof_prbs}); - dlsch_info.tbs = static_cast(tbs_bits); - dlsch_info.mcs_descr = mcs_info; - effective_code_rate = get_dlsch_information(dlsch_info).get_effective_code_rate(); + dlsch_info.tbs = static_cast(tbs_bits); + dlsch_info.mcs_descr = mcs_info; + dlsch_info.contains_dc = contains_dc; + effective_code_rate = get_dlsch_information(dlsch_info).get_effective_code_rate(); } // If no MCS such that effective code rate <= 0.95, return an empty optional object. diff --git a/tests/integrationtests/phy/upper/channel_processors/pxsch_chain_test.cpp b/tests/integrationtests/phy/upper/channel_processors/pxsch_chain_test.cpp index a0073b0804..723b87a27e 100644 --- a/tests/integrationtests/phy/upper/channel_processors/pxsch_chain_test.cpp +++ b/tests/integrationtests/phy/upper/channel_processors/pxsch_chain_test.cpp @@ -206,6 +206,7 @@ TEST_P(PxschChainFixture, Ideal) dlsch_params.dmrs_symbol_mask = dmrs_symbol_mask; dlsch_params.nof_cdm_groups_without_data = 2; dlsch_params.nof_layers = nof_layers; + dlsch_params.contains_dc = true; dlsch_information info = get_dlsch_information(dlsch_params); ASSERT_LT(info.get_effective_code_rate(), 0.95); From 15c0536450a8a9d6c1a188a8136ec3851c4e146a Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 20 Feb 2024 15:24:21 +0100 Subject: [PATCH 008/140] phy,ran: review SCH information related --- include/srsran/ran/direct_current_offset.h | 4 ++-- include/srsran/ran/pdsch/dlsch_info.h | 2 +- include/srsran/ran/pusch/ulsch_info.h | 7 ++++--- lib/ran/pdsch/dlsch_info.cpp | 2 +- lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp | 3 +++ 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/include/srsran/ran/direct_current_offset.h b/include/srsran/ran/direct_current_offset.h index a101024659..607ad6ab8e 100644 --- a/include/srsran/ran/direct_current_offset.h +++ b/include/srsran/ran/direct_current_offset.h @@ -61,7 +61,7 @@ inline uint16_t pack(dc_offset_t offset, unsigned carrier_nof_rbs) /// \param[in] offset DC offset parameter. /// \param[in] carrier_nof_rbs Carrier bandwidth in resource blocks. /// \param[in] rbs Resource block allocation. -/// \return \c true if the DC position is contained. Otherwise \c false. +/// \return \c true if the DC position is contained within the allocated CRBs. Otherwise \c false. inline bool is_contained(dc_offset_t offset, unsigned carrier_nof_rbs, crb_interval rbs) { if (offset == dc_offset_t::undetermined) { @@ -81,7 +81,7 @@ inline bool is_contained(dc_offset_t offset, unsigned carrier_nof_rbs, crb_inter /// \brief Checks if the DC position is contained in a CRB interval. /// \param[in] dc_position DC position in subcarriers within the grid relative to PointA. /// \param[in] rbs Resource block allocation. -/// \return \c true if the DC position is contained. Otherwise \c false. +/// \return \c true if the DC position is contained within the allocated CRBs. Otherwise \c false. inline bool is_contained(unsigned dc_position, crb_interval rbs) { return rbs.contains(dc_position / NOF_SUBCARRIERS_PER_RB); diff --git a/include/srsran/ran/pdsch/dlsch_info.h b/include/srsran/ran/pdsch/dlsch_info.h index e3c8894d2f..b5672afecc 100644 --- a/include/srsran/ran/pdsch/dlsch_info.h +++ b/include/srsran/ran/pdsch/dlsch_info.h @@ -50,7 +50,7 @@ struct dlsch_information { sch_information sch; /// Number of encoded and rate-matched DL-SCH data bits. units::bits nof_dl_sch_bits; - /// Number of bits that are are affected by overlapping with the direct current. + /// Number of bits that are affected by overlapping with the direct current. units::bits nof_dc_overlap_bits; /// \brief Calculates the effective code rate normalized between 0 and 1. diff --git a/include/srsran/ran/pusch/ulsch_info.h b/include/srsran/ran/pusch/ulsch_info.h index 826a0a7960..7acc698995 100644 --- a/include/srsran/ran/pusch/ulsch_info.h +++ b/include/srsran/ran/pusch/ulsch_info.h @@ -85,7 +85,7 @@ struct ulsch_information { unsigned nof_csi_part1_re; /// Number of resource elements occupied by CSI Part 1 information. Parameter \f$Q'_\textup{CSI-2}\f$. unsigned nof_csi_part2_re; - /// Number of bits that are are affected by overlapping with the direct current. + /// Number of bits that are affected by overlapping with the direct current. units::bits nof_dc_overlap_bits; /// \brief Calculates the effective code rate normalized between 0 and 1. @@ -128,9 +128,10 @@ struct ulsch_information { // Adjust the effective rate matched UL-SCH bits considering the bits overlapped with the DC position. if (nof_dc_overlap_bits > 0_bits) { - // Ensure the subtraction of overlapped DC bits does not result in zero or negative. + // Ensure the subtraction of overlapped DC bits does not result in zero or a negative value. srsran_assert(effective_ul_sch_bits > nof_dc_overlap_bits.value(), - "UL-SCH rate match length bits) must be greater than the bits overlapped with DC position ({}).", + "UL-SCH rate match length bits (i.e. {}) must be greater than the bits overlapped with DC position " + "(i.e. {}).", effective_ul_sch_bits, nof_dc_overlap_bits); diff --git a/lib/ran/pdsch/dlsch_info.cpp b/lib/ran/pdsch/dlsch_info.cpp index cef0cac910..ed3aecea05 100644 --- a/lib/ran/pdsch/dlsch_info.cpp +++ b/lib/ran/pdsch/dlsch_info.cpp @@ -82,4 +82,4 @@ dlsch_information srsran::get_dlsch_information(const dlsch_configuration& confi } return result; -} \ No newline at end of file +} diff --git a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp index a684ec6b40..3e9c18344c 100644 --- a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp @@ -272,6 +272,9 @@ alloc_outcome ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& gr optional mcs_tbs_info; // If it's a new Tx, compute the MCS and TBS. if (h_dl.empty()) { + // As \c txDirectCurrentLocation, in \c SCS-SpecificCarrier, TS 38.331, "If this field (\c txDirectCurrentLocation) + // is absent for downlink within ServingCellConfigCommon and ServingCellConfigCommonSIB, the UE assumes the default + // value of 3300 (i.e. "Outside the carrier")". bool contains_dc = false; if (cell_cfg.dl_cfg_common.freq_info_dl.scs_carrier_list.back().tx_direct_current_location.has_value()) { contains_dc = dc_offset_helper::is_contained( From b66e33ec26d0b06f8c189632ab79842bd266aa57 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 23 Feb 2024 15:14:05 +0100 Subject: [PATCH 009/140] phy: fix unset memory --- .../upper/channel_processors/pusch/pusch_processor_unittest.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_unittest.cpp b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_unittest.cpp index 986569be65..4ad528a0a1 100644 --- a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_unittest.cpp +++ b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_unittest.cpp @@ -340,6 +340,7 @@ TEST_P(PuschProcessorFixture, PuschProcessorUnittest) ulsch_config.dmrs_symbol_mask = pdu.dmrs_symbol_mask; ulsch_config.nof_cdm_groups_without_data = pdu.nof_cdm_groups_without_data; ulsch_config.nof_layers = pdu.nof_tx_layers; + ulsch_config.contains_dc = false; ulsch_information ulsch_info = get_ulsch_information(ulsch_config); // Calculate the number of LLR. From d6950cfed7100247b346321a7e2fc2f2eab59b9a Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Fri, 23 Feb 2024 09:01:49 +0100 Subject: [PATCH 010/140] rlc_rx: handle reassembly failures --- lib/rlc/rlc_rx_am_entity.cpp | 31 +++++++++++++++++++++---------- lib/rlc/rlc_rx_um_entity.cpp | 30 +++++++++++++++++++++--------- 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/lib/rlc/rlc_rx_am_entity.cpp b/lib/rlc/rlc_rx_am_entity.cpp index ab951b17e5..7649fec2e7 100644 --- a/lib/rlc/rlc_rx_am_entity.cpp +++ b/lib/rlc/rlc_rx_am_entity.cpp @@ -200,10 +200,15 @@ void rlc_rx_am_entity::handle_data_pdu(byte_buffer_slice buf) * the reassembled RLC SDU to upper layer; */ rlc_rx_am_sdu_info& rx_sdu = (*rx_window)[header.sn]; - logger.log_info("RX SDU. sn={} sdu_len={}", header.sn, rx_sdu.sdu.length()); - metrics.metrics_add_sdus(1, rx_sdu.sdu.length()); - upper_dn.on_new_sdu(std::move(rx_sdu.sdu)); - + if (rx_sdu.sdu.empty()) { + logger.log_error("RX SDU failed: SDU is empty. sn={}", header.sn); + metrics.metrics_add_lost_pdus(1); + // Do not pass empty SDU to upper layers and continue as normal to maintain state + } else { + logger.log_info("RX SDU. sn={} sdu_len={}", header.sn, rx_sdu.sdu.length()); + metrics.metrics_add_sdus(1, rx_sdu.sdu.length()); + upper_dn.on_new_sdu(std::move(rx_sdu.sdu)); + } /* * - if x = RX_Highest_Status, * - update RX_Highest_Status to the SN of the first RLC SDU with SN > current RX_Highest_Status for which not @@ -353,19 +358,25 @@ bool rlc_rx_am_entity::handle_segment_data_sdu(const rlc_am_pdu_header& header, // Check whether all segments have been received update_segment_inventory(rx_sdu); - logger.log_debug("Updated segment inventory. {}", rx_sdu); + logger.log_debug("Updated segment inventory. sn={} {}", header.sn, rx_sdu); if (rx_sdu.fully_received) { // Assemble SDU from segments for (const rlc_rx_am_sdu_segment& segm : rx_sdu.segments) { - logger.log_debug("Chaining segment. so={} len={}", segm.so, segm.payload.length()); + logger.log_debug("Chaining segment. sn={} so={} len={}", header.sn, segm.so, segm.payload.length()); if (not rx_sdu.sdu.append(segm.payload.copy())) { - logger.log_error("Unable to append segment in byte_buffer_chain"); - // Drop SDU if any of the segments failed to be appended. - return false; + logger.log_error("Unable to append segment in byte_buffer_chain. sn={} {}", header.sn, rx_sdu); + // Clear the incomplete SDU to be discarded later before passing it to upper layers. + rx_sdu.sdu.clear(); + break; } } + if (not rx_sdu.sdu.empty()) { + logger.log_debug("Assembled SDU from segments. sn={} sdu_len={}", header.sn, rx_sdu.sdu.length()); + } else { + logger.log_error("Failed to assemble SDU from segments. sn={} {}", header.sn, rx_sdu); + } + // Release segments rx_sdu.segments.clear(); - logger.log_debug("Assembled SDU from segments. sn={} sdu_len={}", header.sn, rx_sdu.sdu.length()); } return stored; } diff --git a/lib/rlc/rlc_rx_um_entity.cpp b/lib/rlc/rlc_rx_um_entity.cpp index 869c5cec4e..80755aeed1 100644 --- a/lib/rlc/rlc_rx_um_entity.cpp +++ b/lib/rlc/rlc_rx_um_entity.cpp @@ -99,9 +99,15 @@ void rlc_rx_um_entity::handle_pdu(byte_buffer_slice buf) * RLC SDU to upper layer; */ rlc_rx_um_sdu_info& rx_sdu = (*rx_window)[header.sn]; - logger.log_info("RX SDU. sn={} sdu_len={}", header.sn, rx_sdu.sdu.length()); - metrics.metrics_add_sdus(1, rx_sdu.sdu.length()); - upper_dn.on_new_sdu(std::move(rx_sdu.sdu)); + if (rx_sdu.sdu.empty()) { + logger.log_error("RX SDU failed: SDU is empty. sn={}", header.sn); + metrics.metrics_add_lost_pdus(1); + // Do not pass empty SDU to upper layers and continue as normal to maintain state + } else { + logger.log_info("RX SDU. sn={} sdu_len={}", header.sn, rx_sdu.sdu.length()); + metrics.metrics_add_sdus(1, rx_sdu.sdu.length()); + upper_dn.on_new_sdu(std::move(rx_sdu.sdu)); + } /* * - if x = RX_Next_Reassembly: @@ -269,19 +275,25 @@ bool rlc_rx_um_entity::handle_segment_data_sdu(const rlc_um_pdu_header& header, // Check whether all segments have been received update_segment_inventory(rx_sdu); - logger.log_debug("Updated segment inventory. {}", rx_sdu); + logger.log_debug("Updated segment inventory. sn={} {}", header.sn, rx_sdu); if (rx_sdu.fully_received) { // Assemble SDU from segments for (const rlc_rx_um_sdu_segment& segm : rx_sdu.segments) { - logger.log_debug("Chaining segment. so={} len={}", segm.so, segm.payload.length()); + logger.log_debug("Chaining segment. sn={} so={} len={}", header.sn, segm.so, segm.payload.length()); if (not rx_sdu.sdu.append(segm.payload.copy())) { - logger.log_error("Unable to append segment in byte_buffer_chain"); - // Drop SDU if any of the segments failed to be appended. - return false; + logger.log_error("Unable to append segment in byte_buffer_chain. sn={} {}", header.sn, rx_sdu); + // Clear the incomplete SDU to be discarded later before passing it to upper layers. + rx_sdu.sdu.clear(); + break; } } + if (not rx_sdu.sdu.empty()) { + logger.log_debug("Assembled SDU from segments. sn={} sdu_len={}", header.sn, rx_sdu.sdu.length()); + } else { + logger.log_error("Failed to assemble SDU from segments. sn={} {}", header.sn, rx_sdu); + } + // Release segments rx_sdu.segments.clear(); - logger.log_debug("Assembled SDU from segments. sn={} sdu_len={}", header.sn, rx_sdu.sdu.length()); } return stored; } From e405c29da4e2a829d46cbc2c3dfea7db72fd4bd6 Mon Sep 17 00:00:00 2001 From: faluco Date: Thu, 22 Feb 2024 12:35:04 +0100 Subject: [PATCH 011/140] srsvec: Misc code cleanups and improvements: - Remove old style C casts that were removing const. - Align with code guidelines. - Use pointer arithmetic when accessing arrays instead of indices. - Fix type punning. --- include/srsran/srsvec/accumulate.h | 5 +-- include/srsran/srsvec/aligned_vec.h | 15 +++++---- include/srsran/srsvec/clip.h | 6 ++-- include/srsran/srsvec/compare.h | 6 ++-- include/srsran/srsvec/division.h | 1 - include/srsran/srsvec/dot_prod.h | 1 - include/srsran/srsvec/modulus_square.h | 1 - include/srsran/srsvec/types.h | 16 +++++----- lib/srsvec/accumulate.cpp | 12 ++++--- lib/srsvec/add.cpp | 43 ++++++++++++++------------ lib/srsvec/aligned_vec.cpp | 4 +-- lib/srsvec/bit.cpp | 25 +++++++-------- lib/srsvec/clip.cpp | 6 ++-- lib/srsvec/compare.cpp | 42 ++++++++++++------------- lib/srsvec/conversion.cpp | 13 ++++---- lib/srsvec/convolution.cpp | 26 +++++----------- lib/srsvec/division.cpp | 9 +++--- lib/srsvec/dot_prod.cpp | 12 ++++--- lib/srsvec/modulus_square.cpp | 10 +++--- lib/srsvec/prod.cpp | 41 ++++++++++++------------ lib/srsvec/sc_prod.cpp | 19 ++++++------ 21 files changed, 148 insertions(+), 165 deletions(-) diff --git a/include/srsran/srsvec/accumulate.h b/include/srsran/srsvec/accumulate.h index 48728fad9f..a76f9e86ea 100644 --- a/include/srsran/srsvec/accumulate.h +++ b/include/srsran/srsvec/accumulate.h @@ -10,10 +10,7 @@ #pragma once -#include "srsran/adt/complex.h" -#include "srsran/srsvec/detail/traits.h" -#include "srsran/support/srsran_assert.h" -#include +#include "srsran/adt/span.h" namespace srsran { namespace srsvec { diff --git a/include/srsran/srsvec/aligned_vec.h b/include/srsran/srsvec/aligned_vec.h index fb3c1a952b..7c6fd7bcd8 100644 --- a/include/srsran/srsvec/aligned_vec.h +++ b/include/srsran/srsvec/aligned_vec.h @@ -20,7 +20,7 @@ void* mem_alloc(std::size_t size); void mem_free(void* ptr); } // namespace detail -/// Type to store a dynamic amount of aligned contiguous elements +/// Type to store a dynamic amount of aligned contiguous elements. template class aligned_vec : public span { @@ -32,22 +32,21 @@ class aligned_vec : public span aligned_vec(const aligned_vec& other) = delete; aligned_vec(aligned_vec&& other) noexcept = delete; - aligned_vec() : span(nullptr, 0UL){}; + aligned_vec() = default; explicit aligned_vec(std::size_t size) { resize(size); } + ~aligned_vec() { dealloc(); } - void resize(unsigned new_size) + void resize(std::size_t new_size) { if (new_size == this->size()) { return; } + dealloc(); - T* ptr_ = (T*)detail::mem_alloc(sizeof(T) * new_size); - span o = span(ptr_, new_size); - *(span*)this = o; + T* p = reinterpret_cast(detail::mem_alloc(sizeof(T) * new_size)); + span::operator=(span(p, new_size)); } - - ~aligned_vec() { dealloc(); } }; } // namespace srsvec diff --git a/include/srsran/srsvec/clip.h b/include/srsran/srsvec/clip.h index 1387d338a1..632922bc20 100644 --- a/include/srsran/srsvec/clip.h +++ b/include/srsran/srsvec/clip.h @@ -33,7 +33,7 @@ namespace srsvec { /// \param [in] x Input Span. /// \param [in] threshold Clipping threshold. /// \return The number of clipped samples. -unsigned clip(span y, span x, const float threshold); +unsigned clip(span y, span x, float threshold); /// \brief Clips the real and imaginary components of a complex span. /// @@ -56,7 +56,7 @@ unsigned clip(span y, span x, const float threshold); /// \param [in] x Input Span. /// \param [in] threshold Clipping threshold. /// \return The number of clipped samples. -unsigned clip_iq(span y, span x, const float threshold); +unsigned clip_iq(span y, span x, float threshold); /// \brief Clips the magnitude of a complex span. /// @@ -73,7 +73,7 @@ unsigned clip_iq(span y, span x, const float threshold); /// \param [in] x Input Span. /// \param [in] threshold Clipping threshold. /// \return The number of clipped samples. -unsigned clip_magnitude(span y, span x, const float threshold); +unsigned clip_magnitude(span y, span x, float threshold); } // namespace srsvec } // namespace srsran diff --git a/include/srsran/srsvec/compare.h b/include/srsran/srsvec/compare.h index aa62c4d1f6..3e3c0d1774 100644 --- a/include/srsran/srsvec/compare.h +++ b/include/srsran/srsvec/compare.h @@ -17,7 +17,7 @@ namespace srsran { namespace srsvec { namespace detail { -const char* find(span input, char value); +const char* find(span input, const char* value); } template @@ -47,7 +47,9 @@ template const T* find(span input, T value) { static_assert(sizeof(T) == 1, "The datatype must be one byte wide."); - return (const T*)detail::find(span((const char*)input.data(), input.size()), *((char*)&value)); + return reinterpret_cast( + detail::find(span(reinterpret_cast(input.data()), input.size()), + reinterpret_cast(&value))); } /// \brief Finds the maximum absolute value in a complex span. diff --git a/include/srsran/srsvec/division.h b/include/srsran/srsvec/division.h index 094c469556..697859adca 100644 --- a/include/srsran/srsvec/division.h +++ b/include/srsran/srsvec/division.h @@ -13,7 +13,6 @@ #include "srsran/srsvec/types.h" namespace srsran { - namespace srsvec { /// \brief Element-wise division between two sequences. diff --git a/include/srsran/srsvec/dot_prod.h b/include/srsran/srsvec/dot_prod.h index f84512aa26..a821c1065a 100644 --- a/include/srsran/srsvec/dot_prod.h +++ b/include/srsran/srsvec/dot_prod.h @@ -17,7 +17,6 @@ #include "srsran/srsvec/detail/traits.h" #include "srsran/srsvec/types.h" #include "srsran/support/srsran_assert.h" - #include namespace srsran { diff --git a/include/srsran/srsvec/modulus_square.h b/include/srsran/srsvec/modulus_square.h index f3bac0653b..88f8b60811 100644 --- a/include/srsran/srsvec/modulus_square.h +++ b/include/srsran/srsvec/modulus_square.h @@ -13,7 +13,6 @@ #include "srsran/srsvec/types.h" namespace srsran { - namespace srsvec { /// \brief Calculates the element-wise modulus square of a sequence of complex values. diff --git a/include/srsran/srsvec/types.h b/include/srsran/srsvec/types.h index 5a2c2c9bac..3957ccccad 100644 --- a/include/srsran/srsvec/types.h +++ b/include/srsran/srsvec/types.h @@ -15,14 +15,14 @@ #include "srsran/support/srsran_assert.h" #include -// The supported vector data types are: -// - srsran::span: For complex float vectors -// - srsran::span: For float vectors -// - srsran::span: For signed 16 bit integer vectors -// - srsran::span: For signed 8 bit integer vectors -// - srsran::span: For unsigned 8 bit integer vectors -// -// To make the span constant use srsran::span. +/// The supported vector data types are: +/// - srsran::span: For complex float vectors +/// - srsran::span: For float vectors +/// - srsran::span: For signed 16 bit integer vectors +/// - srsran::span: For signed 8 bit integer vectors +/// - srsran::span: For unsigned 8 bit integer vectors +/// +/// To make the span constant use srsran::span. #define srsran_srsvec_assert_size(X, Y) \ srsran_assert( \ diff --git a/lib/srsvec/accumulate.cpp b/lib/srsvec/accumulate.cpp index 961ebf7efe..81e3c1bece 100644 --- a/lib/srsvec/accumulate.cpp +++ b/lib/srsvec/accumulate.cpp @@ -9,22 +9,24 @@ */ #include "srsran/srsvec/accumulate.h" #include "simd.h" +#include "srsran/support/srsran_assert.h" +#include using namespace srsran; using namespace srsvec; static float accumulate_f_simd(const float* x, unsigned len) { - float result = 0; + float result = 0; + unsigned i = 0; - unsigned i = 0; #if SRSRAN_SIMD_F_SIZE if (len >= SRSRAN_SIMD_F_SIZE) { - simd_f_t simd_result = srsran_simd_f_loadu(&x[i]); + simd_f_t simd_result = srsran_simd_f_loadu(x + i); i += SRSRAN_SIMD_F_SIZE; for (unsigned simd_end = SRSRAN_SIMD_F_SIZE * (len / SRSRAN_SIMD_F_SIZE); i != simd_end; i += SRSRAN_SIMD_F_SIZE) { - simd_f_t simd_x = srsran_simd_f_loadu(&x[i]); + simd_f_t simd_x = srsran_simd_f_loadu(x + i); simd_result = srsran_simd_f_add(simd_x, simd_result); } @@ -45,4 +47,4 @@ static float accumulate_f_simd(const float* x, unsigned len) float srsran::srsvec::accumulate(span x) { return accumulate_f_simd(x.data(), x.size()); -} \ No newline at end of file +} diff --git a/lib/srsvec/add.cpp b/lib/srsvec/add.cpp index 224ea49d28..96f3c23b5d 100644 --- a/lib/srsvec/add.cpp +++ b/lib/srsvec/add.cpp @@ -21,21 +21,21 @@ static void add_fff_simd(const float* x, const float* y, float* z, std::size_t l #if SRSRAN_SIMD_F_SIZE if (SIMD_IS_ALIGNED(x) && SIMD_IS_ALIGNED(y) && SIMD_IS_ALIGNED(z)) { for (std::size_t i_end = (len / SRSRAN_SIMD_F_SIZE) * SRSRAN_SIMD_F_SIZE; i != i_end; i += SRSRAN_SIMD_F_SIZE) { - simd_f_t a = srsran_simd_f_load(&x[i]); - simd_f_t b = srsran_simd_f_load(&y[i]); + simd_f_t a = srsran_simd_f_load(x + i); + simd_f_t b = srsran_simd_f_load(y + i); simd_f_t r = srsran_simd_f_add(a, b); - srsran_simd_f_store(&z[i], r); + srsran_simd_f_store(z + i, r); } } else { for (std::size_t i_end = (len / SRSRAN_SIMD_F_SIZE) * SRSRAN_SIMD_F_SIZE; i != i_end; i += SRSRAN_SIMD_F_SIZE) { - simd_f_t a = srsran_simd_f_loadu(&x[i]); - simd_f_t b = srsran_simd_f_loadu(&y[i]); + simd_f_t a = srsran_simd_f_loadu(x + i); + simd_f_t b = srsran_simd_f_loadu(y + i); simd_f_t r = srsran_simd_f_add(a, b); - srsran_simd_f_storeu(&z[i], r); + srsran_simd_f_storeu(z + i, r); } } #endif @@ -52,21 +52,21 @@ static void add_sss_simd(const int16_t* x, const int16_t* y, int16_t* z, std::si #if SRSRAN_SIMD_S_SIZE if (SIMD_IS_ALIGNED(x) && SIMD_IS_ALIGNED(y) && SIMD_IS_ALIGNED(z)) { for (std::size_t i_end = (len / SRSRAN_SIMD_S_SIZE) * SRSRAN_SIMD_S_SIZE; i != i_end; i += SRSRAN_SIMD_S_SIZE) { - simd_s_t a = srsran_simd_s_load(&x[i]); - simd_s_t b = srsran_simd_s_load(&y[i]); + simd_s_t a = srsran_simd_s_load(x + i); + simd_s_t b = srsran_simd_s_load(y + i); simd_s_t r = srsran_simd_s_add(a, b); - srsran_simd_s_store(&z[i], r); + srsran_simd_s_store(z + i, r); } } else { for (std::size_t i_end = (len / SRSRAN_SIMD_S_SIZE) * SRSRAN_SIMD_S_SIZE; i != i_end; i += SRSRAN_SIMD_S_SIZE) { - simd_s_t a = srsran_simd_s_loadu(&x[i]); - simd_s_t b = srsran_simd_s_loadu(&y[i]); + simd_s_t a = srsran_simd_s_loadu(x + i); + simd_s_t b = srsran_simd_s_loadu(y + i); simd_s_t r = srsran_simd_s_add(a, b); - srsran_simd_s_storeu(&z[i], r); + srsran_simd_s_storeu(z + i, r); } } #endif /* SRSRAN_SIMD_S_SIZE */ @@ -83,21 +83,21 @@ static void add_bbb_simd(const int8_t* x, const int8_t* y, int8_t* z, std::size_ #if SRSRAN_SIMD_S_SIZE if (SIMD_IS_ALIGNED(x) && SIMD_IS_ALIGNED(y) && SIMD_IS_ALIGNED(z)) { for (std::size_t i_end = (len / SRSRAN_SIMD_B_SIZE) * SRSRAN_SIMD_B_SIZE; i != i_end; i += SRSRAN_SIMD_B_SIZE) { - simd_b_t a = srsran_simd_b_load(&x[i]); - simd_b_t b = srsran_simd_b_load(&y[i]); + simd_b_t a = srsran_simd_b_load(x + i); + simd_b_t b = srsran_simd_b_load(y + i); simd_b_t r = srsran_simd_b_add(a, b); - srsran_simd_b_store(&z[i], r); + srsran_simd_b_store(z + i, r); } } else { for (std::size_t i_end = (len / SRSRAN_SIMD_B_SIZE) * SRSRAN_SIMD_B_SIZE; i != i_end; i += SRSRAN_SIMD_B_SIZE) { - simd_b_t a = srsran_simd_b_loadu(&x[i]); - simd_b_t b = srsran_simd_b_loadu(&y[i]); + simd_b_t a = srsran_simd_b_loadu(x + i); + simd_b_t b = srsran_simd_b_loadu(y + i); simd_b_t r = srsran_simd_b_add(a, b); - srsran_simd_b_storeu(&z[i], r); + srsran_simd_b_storeu(z + i, r); } } #endif /* SRSRAN_SIMD_S_SIZE */ @@ -112,7 +112,10 @@ void srsran::srsvec::add(span x, span y, span z) srsran_srsvec_assert_size(x, y); srsran_srsvec_assert_size(x, z); - add_fff_simd((float*)x.data(), (float*)y.data(), (float*)z.data(), 2 * z.size()); + add_fff_simd(reinterpret_cast(x.data()), + reinterpret_cast(y.data()), + reinterpret_cast(z.data()), + 2 * z.size()); } void srsran::srsvec::add(span x, span y, span z) @@ -137,4 +140,4 @@ void srsran::srsvec::add(span x, span y, span -void unpack_8bit(span unpacked, InType value) +static void unpack_8bit(span unpacked, InType value) { srsran_assert(unpacked.size() == 8, "The amount of data to pack (i.e., {}) must be eight.", unpacked.size()); @@ -36,7 +34,7 @@ void unpack_8bit(span unpacked, InType value) } template -RetType pack_8bit(span unpacked) +static RetType pack_8bit(span unpacked) { srsran_assert(unpacked.size() == 8, "The amount of data to pack (i.e., {}) must be eight.", unpacked.size()); @@ -53,13 +51,11 @@ RetType pack_8bit(span unpacked) return static_cast(packed); } -} // namespace - span srsran::srsvec::bit_unpack(span bits, unsigned value, unsigned nof_bits) { srsran_assert(bits.size() >= nof_bits, "Input span size is too small"); - for (unsigned i = 0; i < nof_bits; i++) { + for (unsigned i = 0; i != nof_bits; ++i) { bits[i] = (value >> (nof_bits - i - 1)) & 0x1; } @@ -202,7 +198,7 @@ unsigned srsran::srsvec::bit_pack(span& bits, unsigned nof_bits) unsigned value = 0; - for (unsigned i = 0; i < nof_bits; i++) { + for (unsigned i = 0; i != nof_bits; ++i) { value |= (unsigned)bits[i] << (nof_bits - i - 1U); } @@ -323,14 +319,15 @@ void srsran::srsvec::copy_offset(srsran::bit_buffer& output, span unsigned i_word = 0; #ifdef __AVX2__ for (unsigned i_word_end = (nof_full_words / 32) * 32; i_word != i_word_end; i_word += 32) { - __m256i word0 = _mm256_loadu_si256(reinterpret_cast(&input[input_start_word + i_word])); - __m256i word1 = _mm256_loadu_si256(reinterpret_cast(&input[input_start_word + i_word + 1])); - word0 = _mm256_and_si256(_mm256_slli_epi32(word0, input_start_mod), + __m256i word0 = _mm256_loadu_si256(reinterpret_cast(input.data() + input_start_word + i_word)); + __m256i word1 = + _mm256_loadu_si256(reinterpret_cast(input.data() + input_start_word + i_word + 1)); + word0 = _mm256_and_si256(_mm256_slli_epi32(word0, input_start_mod), _mm256_set1_epi8(mask_msb_ones(bits_per_word - input_start_mod))); - word1 = _mm256_and_si256(_mm256_srli_epi32(word1, bits_per_word - input_start_mod), + word1 = _mm256_and_si256(_mm256_srli_epi32(word1, bits_per_word - input_start_mod), _mm256_set1_epi8(mask_lsb_ones(input_start_mod))); - __m256i word = _mm256_or_si256(word0, word1); - _mm256_storeu_si256(reinterpret_cast<__m256i*>(&buffer[i_word]), word); + __m256i word = _mm256_or_si256(word0, word1); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(buffer.data() + i_word), word); } #endif // __AVX2__ for (; i_word != nof_full_words; ++i_word) { diff --git a/lib/srsvec/clip.cpp b/lib/srsvec/clip.cpp index 2569da265d..4f9e3972d6 100644 --- a/lib/srsvec/clip.cpp +++ b/lib/srsvec/clip.cpp @@ -13,7 +13,7 @@ using namespace srsran; -unsigned srsvec::clip(span y, span x, const float threshold) +unsigned srsvec::clip(span y, span x, float threshold) { srsran_srsvec_assert_size(x, y); @@ -36,14 +36,14 @@ unsigned srsvec::clip(span y, span x, const float threshold) return nof_clipped_samples; } -unsigned srsvec::clip_iq(span y, span x, const float threshold) +unsigned srsvec::clip_iq(span y, span x, float threshold) { span x_fp = span(reinterpret_cast(x.data()), 2 * x.size()); span y_fp = span(reinterpret_cast(y.data()), 2 * x.size()); return srsvec::clip(y_fp, x_fp, threshold); } -unsigned srsvec::clip_magnitude(span y, span x, const float threshold) +unsigned srsvec::clip_magnitude(span y, span x, float threshold) { srsran_srsvec_assert_size(x, y); diff --git a/lib/srsvec/compare.cpp b/lib/srsvec/compare.cpp index 9659e2d139..6474c0af49 100644 --- a/lib/srsvec/compare.cpp +++ b/lib/srsvec/compare.cpp @@ -9,7 +9,6 @@ */ #include "srsran/srsvec/compare.h" - #include "simd.h" #include "srsran/support/math_utils.h" #include @@ -17,18 +16,19 @@ using namespace srsran; using namespace srsvec; -const char* srsran::srsvec::detail::find(span input, char value) +const char* srsran::srsvec::detail::find(span input, const char* value) { // Input index. unsigned index = 0; + char v = *value; #ifdef HAVE_AVX2 // Advances the input index to either the first SIMD word that contains value or the last index rounded to 32. for (unsigned simd_index_end = 32 * (input.size() / 32); index != simd_index_end; index += 32) { // Load 32 consecutive words starting at index. - __m256i simd_input = _mm256_loadu_si256((__m256i*)&input[index]); + __m256i simd_input = _mm256_loadu_si256(reinterpret_cast(input.data() + index)); // Compare the 32 words with the value. - __m256i simd_eq_filler_bit = _mm256_cmpeq_epi8(_mm256_set1_epi8(value), simd_input); + __m256i simd_eq_filler_bit = _mm256_cmpeq_epi8(_mm256_set1_epi8(v), simd_input); // Get the MSB of each word. unsigned mask = _mm256_movemask_epi8(simd_eq_filler_bit); // If it is not zero, it means at least one of the words in the SIMD register is equal to value. @@ -43,7 +43,7 @@ const char* srsran::srsvec::detail::find(span input, char value) // Advances the input index to either the first SIMD word that contains value or the last index rounded to 16. for (unsigned simd_index_end = 16 * (input.size() / 16); index != simd_index_end; index += 16) { // Load 16 consecutive words starting at index. - int8x16_t simd_input = vld1q_s8(reinterpret_cast(&input[index])); + int8x16_t simd_input = vld1q_s8(reinterpret_cast(input.data() + index)); // Compare the 16 words with the value. uint8x16_t mask_u8 = vceqq_s8(vdupq_n_s8((int8_t)value), simd_input); uint8_t mask = vmaxvq_u8(mask_u8); @@ -55,7 +55,7 @@ const char* srsran::srsvec::detail::find(span input, char value) // Advances the input index to either the first SIMD word that contains value or the last index rounded to 8. for (unsigned simd_index_end = 8 * (input.size() / 8); !found && index != simd_index_end; index += 8) { // Load 8 consecutive words starting at index. - int8x8_t simd_input = vld1_s8(reinterpret_cast(&input[index])); + int8x8_t simd_input = vld1_s8(reinterpret_cast(input.data() + index)); // Compare the 8 words with the value. uint8x8_t mask_u8 = vceq_s8(vdup_n_s8((int8_t)value), simd_input); uint8_t mask = vmaxv_u8(mask_u8); @@ -68,7 +68,7 @@ const char* srsran::srsvec::detail::find(span input, char value) // Keeps iterating from the current index to the end. for (; index != input.size(); ++index) { // Early return if a word is equal to value. - if (input[index] == value) { + if (input[index] == v) { return &input[index]; } } @@ -79,10 +79,8 @@ const char* srsran::srsvec::detail::find(span input, char value) std::pair srsran::srsvec::max_abs_element(span x) { - unsigned max_index = 0; - float max_abs2 = 0.0F; - - unsigned i = 0, len = x.size(); + unsigned i = 0; + unsigned len = x.size(); #if SRSRAN_SIMD_CF_SIZE // Prepare range of indexes in SIMD register. @@ -97,8 +95,8 @@ std::pair srsran::srsvec::max_abs_element(span x) for (unsigned simd_end = SRSRAN_SIMD_CF_SIZE * (len / SRSRAN_SIMD_CF_SIZE); i != simd_end; i += SRSRAN_SIMD_CF_SIZE) { // Load 2 SIMD words of floats. - simd_f_t simd_x1 = srsran_simd_f_loadu((float*)&x[i]); - simd_f_t simd_x2 = srsran_simd_f_loadu((float*)&x[i + SRSRAN_SIMD_CF_SIZE / 2]); + simd_f_t simd_x1 = srsran_simd_f_loadu(reinterpret_cast(x.data() + i)); + simd_f_t simd_x2 = srsran_simd_f_loadu(reinterpret_cast(x.data() + i + SRSRAN_SIMD_CF_SIZE / 2)); // Calculates the squares. simd_f_t simd_mul1 = srsran_simd_f_mul(simd_x1, simd_x1); @@ -126,8 +124,8 @@ std::pair srsran::srsvec::max_abs_element(span x) // Find maximum value within the vectors. float* it = std::max_element(simd_vector_max_values.begin(), simd_vector_max_values.end()); unsigned simd_max_index = static_cast(it - simd_vector_max_values.begin()); - max_index = simd_vector_max_indexes[simd_max_index]; - max_abs2 = simd_vector_max_values[simd_max_index]; + unsigned max_index = simd_vector_max_indexes[simd_max_index]; + float max_abs2 = simd_vector_max_values[simd_max_index]; #endif // SRSRAN_SIMD_CF_SIZE for (; i != len; ++i) { @@ -143,10 +141,8 @@ std::pair srsran::srsvec::max_abs_element(span x) std::pair srsran::srsvec::max_element(span x) { - unsigned max_index = 0; - float max_x = 0.0F; - - unsigned i = 0, len = x.size(); + unsigned i = 0; + unsigned len = x.size(); #if SRSRAN_SIMD_CF_SIZE // Prepare range of indexes in SIMD register. @@ -161,7 +157,7 @@ std::pair srsran::srsvec::max_element(span x) for (unsigned simd_end = SRSRAN_SIMD_CF_SIZE * (len / SRSRAN_SIMD_CF_SIZE); i != simd_end; i += SRSRAN_SIMD_CF_SIZE) { // Load SIMD word of floats. - simd_f_t simd_x = srsran_simd_f_loadu((float*)&x[i]); + simd_f_t simd_x = srsran_simd_f_loadu(reinterpret_cast(x.data() + i)); // Get SIMD selector mask. simd_sel_t res = srsran_simd_f_max(simd_x, simd_max_values); @@ -182,8 +178,8 @@ std::pair srsran::srsvec::max_element(span x) // Find maximum value within the vectors. float* it = std::max_element(simd_vector_max_values.begin(), simd_vector_max_values.end()); unsigned simd_max_index = static_cast(it - simd_vector_max_values.begin()); - max_index = simd_vector_max_indexes[simd_max_index]; - max_x = simd_vector_max_values[simd_max_index]; + unsigned max_index = simd_vector_max_indexes[simd_max_index]; + float max_x = simd_vector_max_values[simd_max_index]; #endif // SRSRAN_SIMD_CF_SIZE for (; i != len; ++i) { @@ -194,4 +190,4 @@ std::pair srsran::srsvec::max_element(span x) } return {max_index, max_x}; -} \ No newline at end of file +} diff --git a/lib/srsvec/conversion.cpp b/lib/srsvec/conversion.cpp index 112e3e5206..d7b2d4a9fe 100644 --- a/lib/srsvec/conversion.cpp +++ b/lib/srsvec/conversion.cpp @@ -9,7 +9,6 @@ */ #include "srsran/srsvec/conversion.h" - #include "simd.h" using namespace srsran; @@ -23,27 +22,27 @@ static inline void convert_fi_simd(const float* x, int16_t* z, float scale, unsi simd_f_t s = srsran_simd_f_set1(scale); if (SIMD_IS_ALIGNED(x) && SIMD_IS_ALIGNED(z)) { for (; i + SRSRAN_SIMD_S_SIZE < len + 1; i += SRSRAN_SIMD_S_SIZE) { - simd_f_t a = srsran_simd_f_load(&x[i]); - simd_f_t b = srsran_simd_f_load(&x[i + SRSRAN_SIMD_F_SIZE]); + simd_f_t a = srsran_simd_f_load(x + i); + simd_f_t b = srsran_simd_f_load(x + i + SRSRAN_SIMD_F_SIZE); simd_f_t sa = srsran_simd_f_mul(a, s); simd_f_t sb = srsran_simd_f_mul(b, s); simd_s_t i16 = srsran_simd_convert_2f_s(sa, sb); - srsran_simd_s_store(&z[i], i16); + srsran_simd_s_store(z + i, i16); } } else { for (; i + SRSRAN_SIMD_S_SIZE < len + 1; i += SRSRAN_SIMD_S_SIZE) { - simd_f_t a = srsran_simd_f_loadu(&x[i]); - simd_f_t b = srsran_simd_f_loadu(&x[i + SRSRAN_SIMD_F_SIZE]); + simd_f_t a = srsran_simd_f_loadu(x + i); + simd_f_t b = srsran_simd_f_loadu(x + i + SRSRAN_SIMD_F_SIZE); simd_f_t sa = srsran_simd_f_mul(a, s); simd_f_t sb = srsran_simd_f_mul(b, s); simd_s_t i16 = srsran_simd_convert_2f_s(sa, sb); - srsran_simd_s_storeu(&z[i], i16); + srsran_simd_s_storeu(z + i, i16); } } #endif /* SRSRAN_SIMD_F_SIZE && SRSRAN_SIMD_S_SIZE */ diff --git a/lib/srsvec/convolution.cpp b/lib/srsvec/convolution.cpp index 704f469b18..b7a2d94d23 100644 --- a/lib/srsvec/convolution.cpp +++ b/lib/srsvec/convolution.cpp @@ -15,11 +15,7 @@ using namespace srsran; using namespace srsvec; -namespace srsran { -namespace srsvec { -namespace detail { - -void multiply_and_accumulate(span out, span x, span y) +void srsran::srsvec::detail::multiply_and_accumulate(span out, span x, span y) { unsigned y_mid = y.size() / 2; unsigned out_start = y_mid - (y.size() % 2 == 0 ? 1 : 0); @@ -32,15 +28,13 @@ void multiply_and_accumulate(span out, span x, span x_chunk = x.subspan(x_start, x_end - x_start); - unsigned i = 0; - - for (unsigned i_end = x_chunk.size(); i != i_end; ++i) { + for (unsigned i = 0, i_end = x_chunk.size(); i != i_end; ++i) { out[i + out_start] += x_chunk[i] * y[y_index]; } } } -void multiply_and_accumulate(span out, span x, span y) +void srsran::srsvec::detail::multiply_and_accumulate(span out, span x, span y) { unsigned y_mid = y.size() / 2; unsigned out_start = (y_mid - (y.size() % 2 == 0 ? 1 : 0)) * 2; @@ -57,11 +51,11 @@ void multiply_and_accumulate(span out, span x, span out, span x, span out, span x, span y) +void srsran::srsvec::detail::multiply_and_accumulate(span out, span x, span y) { unsigned y_mid = y.size() / 2; unsigned out_start = y_mid - (y.size() % 2 == 0 ? 1 : 0); @@ -91,14 +85,8 @@ void multiply_and_accumulate(span out, span x, span x_chunk = x.subspan(x_start, x_end - x_start); - unsigned i = 0; - - for (unsigned i_end = x_chunk.size(); i != i_end; ++i) { + for (unsigned i = 0, i_end = x_chunk.size(); i != i_end; ++i) { out[i + out_start] += x_chunk[i] * y[y_index]; } } } - -} // namespace detail -} // namespace srsvec -} // namespace srsran diff --git a/lib/srsvec/division.cpp b/lib/srsvec/division.cpp index 8f09d95a6b..ed888060ce 100644 --- a/lib/srsvec/division.cpp +++ b/lib/srsvec/division.cpp @@ -12,6 +12,7 @@ #include "simd.h" using namespace srsran; +using namespace srsvec; static void divide_fff_simd(float* result, const float* num, const float* den, std::size_t len) { @@ -19,12 +20,12 @@ static void divide_fff_simd(float* result, const float* num, const float* den, s #if SRSRAN_SIMD_F_SIZE for (; i + SRSRAN_SIMD_F_SIZE < len + 1; i += SRSRAN_SIMD_F_SIZE) { - simd_f_t num_simd = srsran_simd_f_loadu(&num[i]); - simd_f_t den_simd = srsran_simd_f_loadu(&den[i]); + simd_f_t num_simd = srsran_simd_f_loadu(num + i); + simd_f_t den_simd = srsran_simd_f_loadu(den + i); simd_f_t r = srsran_simd_f_mul(num_simd, srsran_simd_f_rcp(den_simd)); - srsran_simd_f_storeu(&result[i], r); + srsran_simd_f_storeu(result + i, r); } #endif @@ -44,4 +45,4 @@ void srsran::srsvec::divide(span result, span numerator, spa srsran_srsvec_assert_size(result, denominator); divide_fff_simd(result.data(), numerator.data(), denominator.data(), result.size()); -} \ No newline at end of file +} diff --git a/lib/srsvec/dot_prod.cpp b/lib/srsvec/dot_prod.cpp index a63f9d8167..7d860843a7 100644 --- a/lib/srsvec/dot_prod.cpp +++ b/lib/srsvec/dot_prod.cpp @@ -9,24 +9,26 @@ */ #include "srsran/srsvec/dot_prod.h" - #include "simd.h" using namespace srsran; +using namespace srsvec; cf_t srsran::srsvec::dot_prod(span x, span y) { - cf_t result = 0; srsran_srsvec_assert_size(x, y); - unsigned i = 0, len = x.size(); + cf_t result = 0; + unsigned i = 0; + unsigned len = x.size(); + #if SRSRAN_SIMD_CF_SIZE if (len >= SRSRAN_SIMD_CF_SIZE) { simd_cf_t simd_result = srsran_simd_cf_zero(); for (unsigned simd_end = SRSRAN_SIMD_CF_SIZE * (len / SRSRAN_SIMD_CF_SIZE); i != simd_end; i += SRSRAN_SIMD_CF_SIZE) { - simd_cf_t simd_x = srsran_simd_cfi_loadu(&x[i]); - simd_cf_t simd_y = srsran_simd_cfi_loadu(&y[i]); + simd_cf_t simd_x = srsran_simd_cfi_loadu(x.data() + i); + simd_cf_t simd_y = srsran_simd_cfi_loadu(y.data() + i); simd_result = srsran_simd_cf_add(srsran_simd_cf_conjprod(simd_x, simd_y), simd_result); } diff --git a/lib/srsvec/modulus_square.cpp b/lib/srsvec/modulus_square.cpp index a6a3949c87..9aac36d415 100644 --- a/lib/srsvec/modulus_square.cpp +++ b/lib/srsvec/modulus_square.cpp @@ -12,6 +12,7 @@ #include "simd.h" using namespace srsran; +using namespace srsvec; static void modulus_square_simd(float* result, const cf_t* input, std::size_t len) { @@ -20,8 +21,8 @@ static void modulus_square_simd(float* result, const cf_t* input, std::size_t le #if SRSRAN_SIMD_CF_SIZE for (unsigned simd_end = SRSRAN_SIMD_CF_SIZE * (len / SRSRAN_SIMD_CF_SIZE); i != simd_end; i += SRSRAN_SIMD_CF_SIZE) { // Load 2 SIMD words of floats. - simd_f_t simd_input1 = srsran_simd_f_loadu((float*)&input[i]); - simd_f_t simd_input2 = srsran_simd_f_loadu((float*)&input[i + SRSRAN_SIMD_CF_SIZE / 2]); + simd_f_t simd_input1 = srsran_simd_f_loadu(reinterpret_cast(input + i)); + simd_f_t simd_input2 = srsran_simd_f_loadu(reinterpret_cast(input + i + SRSRAN_SIMD_CF_SIZE / 2)); // Calculates the squares. simd_f_t simd_mul1 = srsran_simd_f_mul(simd_input1, simd_input1); @@ -30,7 +31,7 @@ static void modulus_square_simd(float* result, const cf_t* input, std::size_t le // Horizontally add the values in pair, it results in adding the squared real and imaginary parts. simd_f_t simd_abs2 = srsran_simd_f_hadd(simd_mul1, simd_mul2); - srsran_simd_f_storeu(&result[i], simd_abs2); + srsran_simd_f_storeu(result + i, simd_abs2); } #endif // SRSRAN_SIMD_CF_SIZE @@ -45,5 +46,6 @@ static void modulus_square_simd(float* result, const cf_t* input, std::size_t le void srsran::srsvec::modulus_square(span result, span input) { srsran_srsvec_assert_size(result, input); + modulus_square_simd(result.data(), input.data(), input.size()); -} \ No newline at end of file +} diff --git a/lib/srsvec/prod.cpp b/lib/srsvec/prod.cpp index dd3e673322..54ac141cb8 100644 --- a/lib/srsvec/prod.cpp +++ b/lib/srsvec/prod.cpp @@ -9,9 +9,8 @@ */ #include "srsran/srsvec/prod.h" -#include - #include "simd.h" +#include using namespace srsran; using namespace srsvec; @@ -23,21 +22,21 @@ static void prod_fff_simd(const float* x, const float* y, float* z, std::size_t #if SRSRAN_SIMD_F_SIZE if (SIMD_IS_ALIGNED(x) && SIMD_IS_ALIGNED(y) && SIMD_IS_ALIGNED(z)) { for (; i + SRSRAN_SIMD_F_SIZE < len + 1; i += SRSRAN_SIMD_F_SIZE) { - simd_f_t a = srsran_simd_f_load(&x[i]); - simd_f_t b = srsran_simd_f_load(&y[i]); + simd_f_t a = srsran_simd_f_load(x + i); + simd_f_t b = srsran_simd_f_load(y + i); simd_f_t r = srsran_simd_f_mul(a, b); - srsran_simd_f_store(&z[i], r); + srsran_simd_f_store(z + i, r); } } else { for (; i + SRSRAN_SIMD_F_SIZE < len + 1; i += SRSRAN_SIMD_F_SIZE) { - simd_f_t a = srsran_simd_f_loadu(&x[i]); - simd_f_t b = srsran_simd_f_loadu(&y[i]); + simd_f_t a = srsran_simd_f_loadu(x + i); + simd_f_t b = srsran_simd_f_loadu(y + i); simd_f_t r = srsran_simd_f_mul(a, b); - srsran_simd_f_storeu(&z[i], r); + srsran_simd_f_storeu(z + i, r); } } #endif @@ -54,21 +53,21 @@ static void prod_ccc_simd(const cf_t* x, const cf_t* y, cf_t* z, std::size_t len #if SRSRAN_SIMD_CF_SIZE if (SIMD_IS_ALIGNED(x) && SIMD_IS_ALIGNED(y) && SIMD_IS_ALIGNED(z)) { for (std::size_t i_end = (len / SRSRAN_SIMD_CF_SIZE) * SRSRAN_SIMD_CF_SIZE; i != i_end; i += SRSRAN_SIMD_CF_SIZE) { - simd_cf_t a = srsran_simd_cfi_load(&x[i]); - simd_cf_t b = srsran_simd_cfi_load(&y[i]); + simd_cf_t a = srsran_simd_cfi_load(x + i); + simd_cf_t b = srsran_simd_cfi_load(y + i); simd_cf_t r = srsran_simd_cf_prod(a, b); - srsran_simd_cfi_store(&z[i], r); + srsran_simd_cfi_store(z + i, r); } } else { for (std::size_t i_end = (len / SRSRAN_SIMD_CF_SIZE) * SRSRAN_SIMD_CF_SIZE; i != i_end; i += SRSRAN_SIMD_CF_SIZE) { - simd_cf_t a = srsran_simd_cfi_loadu(&x[i]); - simd_cf_t b = srsran_simd_cfi_loadu(&y[i]); + simd_cf_t a = srsran_simd_cfi_loadu(x + i); + simd_cf_t b = srsran_simd_cfi_loadu(y + i); simd_cf_t r = srsran_simd_cf_prod(a, b); - srsran_simd_cfi_storeu(&z[i], r); + srsran_simd_cfi_storeu(z + i, r); } } #endif @@ -85,21 +84,21 @@ static void prod_conj_ccc_simd(const cf_t* x, const cf_t* y, cf_t* z, std::size_ #if SRSRAN_SIMD_CF_SIZE if (SIMD_IS_ALIGNED(x) && SIMD_IS_ALIGNED(y) && SIMD_IS_ALIGNED(z)) { for (std::size_t i_end = (len / SRSRAN_SIMD_CF_SIZE) * SRSRAN_SIMD_CF_SIZE; i != i_end; i += SRSRAN_SIMD_CF_SIZE) { - simd_cf_t a = srsran_simd_cfi_load(&x[i]); - simd_cf_t b = srsran_simd_cfi_load(&y[i]); + simd_cf_t a = srsran_simd_cfi_load(x + i); + simd_cf_t b = srsran_simd_cfi_load(y + i); simd_cf_t r = srsran_simd_cf_conjprod(a, b); - srsran_simd_cfi_store(&z[i], r); + srsran_simd_cfi_store(z + i, r); } } else { for (std::size_t i_end = (len / SRSRAN_SIMD_CF_SIZE) * SRSRAN_SIMD_CF_SIZE; i != i_end; i += SRSRAN_SIMD_CF_SIZE) { - simd_cf_t a = srsran_simd_cfi_loadu(&x[i]); - simd_cf_t b = srsran_simd_cfi_loadu(&y[i]); + simd_cf_t a = srsran_simd_cfi_loadu(x + i); + simd_cf_t b = srsran_simd_cfi_loadu(y + i); simd_cf_t r = srsran_simd_cf_conjprod(a, b); - srsran_simd_cfi_storeu(&z[i], r); + srsran_simd_cfi_storeu(z + i, r); } } #endif @@ -131,4 +130,4 @@ void srsran::srsvec::prod_conj(span x, span y, span x, float h, span z) { srsran_srsvec_assert_size(x, z); - sc_prod_fff_simd((float*)x.data(), h, (float*)z.data(), 2 * x.size()); + sc_prod_fff_simd(reinterpret_cast(x.data()), h, reinterpret_cast(z.data()), 2 * x.size()); } void srsran::srsvec::sc_prod(span x, float h, span z) From fa18f58e92e88e396b311db0dc2c0c5b7cba9cd5 Mon Sep 17 00:00:00 2001 From: faluco Date: Thu, 22 Feb 2024 14:10:38 +0100 Subject: [PATCH 012/140] srsvec: Modernize simd.h file to C++ --- lib/srsvec/add.cpp | 6 +- lib/srsvec/bit.cpp | 2 +- lib/srsvec/conversion.cpp | 4 +- lib/srsvec/sc_prod.cpp | 4 +- lib/srsvec/simd.h | 586 ++++++++++++++++++++------------------ lib/srsvec/subtract.cpp | 8 +- 6 files changed, 321 insertions(+), 289 deletions(-) diff --git a/lib/srsvec/add.cpp b/lib/srsvec/add.cpp index 96f3c23b5d..1071b9d866 100644 --- a/lib/srsvec/add.cpp +++ b/lib/srsvec/add.cpp @@ -40,7 +40,7 @@ static void add_fff_simd(const float* x, const float* y, float* z, std::size_t l } #endif - for (; i != len; i++) { + for (; i != len; ++i) { z[i] = x[i] + y[i]; } } @@ -71,7 +71,7 @@ static void add_sss_simd(const int16_t* x, const int16_t* y, int16_t* z, std::si } #endif /* SRSRAN_SIMD_S_SIZE */ - for (; i != len; i++) { + for (; i != len; ++i) { z[i] = x[i] + y[i]; } } @@ -102,7 +102,7 @@ static void add_bbb_simd(const int8_t* x, const int8_t* y, int8_t* z, std::size_ } #endif /* SRSRAN_SIMD_S_SIZE */ - for (; i != len; i++) { + for (; i != len; ++i) { z[i] = x[i] + y[i]; } } diff --git a/lib/srsvec/bit.cpp b/lib/srsvec/bit.cpp index 4cf2868097..ecde69c464 100644 --- a/lib/srsvec/bit.cpp +++ b/lib/srsvec/bit.cpp @@ -214,7 +214,7 @@ unsigned srsran::srsvec::bit_pack(span bits) unsigned value = 0; - for (unsigned i = 0, nof_bits = bits.size(); i != nof_bits; i++) { + for (unsigned i = 0, nof_bits = bits.size(); i != nof_bits; ++i) { value |= (unsigned)bits[i] << (nof_bits - i - 1U); } diff --git a/lib/srsvec/conversion.cpp b/lib/srsvec/conversion.cpp index d7b2d4a9fe..efd26f54c7 100644 --- a/lib/srsvec/conversion.cpp +++ b/lib/srsvec/conversion.cpp @@ -47,7 +47,7 @@ static inline void convert_fi_simd(const float* x, int16_t* z, float scale, unsi } #endif /* SRSRAN_SIMD_F_SIZE && SRSRAN_SIMD_S_SIZE */ - for (; i != len; i++) { + for (; i != len; ++i) { z[i] = static_cast(std::round(x[i] * scale)); } } @@ -112,7 +112,7 @@ static inline void convert_if_simd(float* z, const int16_t* x, float scale, unsi } #endif // defined(__AVX__) && defined(__AVX2__) - for (; i != len; i++) { + for (; i != len; ++i) { z[i] = static_cast(x[i]) * gain; } } diff --git a/lib/srsvec/sc_prod.cpp b/lib/srsvec/sc_prod.cpp index 065ca0b21a..dffaf9c097 100644 --- a/lib/srsvec/sc_prod.cpp +++ b/lib/srsvec/sc_prod.cpp @@ -39,7 +39,7 @@ static void sc_prod_fff_simd(const float* x, float h, float* z, std::size_t len) } #endif - for (; i != len; i++) { + for (; i != len; ++i) { z[i] = x[i] * h; } } @@ -69,7 +69,7 @@ static void sc_prod_ccc_simd(const cf_t* x, cf_t h, cf_t* z, std::size_t len) } #endif - for (; i != len; i++) { + for (; i != len; ++i) { z[i] = x[i] * h; } } diff --git a/lib/srsvec/simd.h b/lib/srsvec/simd.h index b5ae3dfe06..330957a418 100644 --- a/lib/srsvec/simd.h +++ b/lib/srsvec/simd.h @@ -45,29 +45,44 @@ inline bool is_simd_addr_aligned(const void* addr, uintptr_t mask) return (addr_i & mask) == 0; } -/* - * SIMD Vector bit alignment - */ -#ifdef HAVE_AVX512 -#define SIMD_BYTE_ALIGN 64 -#define SIMD_IS_ALIGNED(PTR) is_simd_addr_aligned(PTR, 0x3f) +/// +/// SIMD Vector bit alignment. +/// +#ifdef HAVE_AVX512 +constexpr unsigned SIMD_BYTE_ALIGN = 64; +inline bool SIMD_IS_ALIGNED(const void* ptr) +{ + return is_simd_addr_aligned(ptr, 0x3f); +} #else /* HAVE_AVX512 */ #ifdef HAVE_AVX -#define SIMD_BYTE_ALIGN 32 -#define SIMD_IS_ALIGNED(PTR) is_simd_addr_aligned(PTR, 0x1f) +constexpr unsigned SIMD_BYTE_ALIGN = 32; +inline bool SIMD_IS_ALIGNED(const void* ptr) +{ + return is_simd_addr_aligned(ptr, 0x1f); +} #else /* HAVE_AVX */ #ifdef HAVE_SSE -#define SIMD_BYTE_ALIGN 16 -#define SIMD_IS_ALIGNED(PTR) is_simd_addr_aligned(PTR, 0x0f) -#else /* HAVE_SSE */ -#define SIMD_BYTE_ALIGN 16 -#define SIMD_IS_ALIGNED(PTR) (true) +constexpr unsigned SIMD_BYTE_ALIGN = 16; +inline bool SIMD_IS_ALIGNED(const void* ptr) +{ + return is_simd_addr_aligned(ptr, 0x0f); +} +#else /* HAVE_SSE */ +constexpr unsigned SIMD_BYTE_ALIGN = 16; +inline bool SIMD_IS_ALIGNED(const void* ptr) +{ + return true; +} #endif /* HAVE_SSE */ #endif /* HAVE_AVX */ #endif /* HAVE_AVX512 */ -/* Memory Sizes for Single Floating Point and fixed point */ +/// +/// Memory Sizes for Single Floating Point and fixed point. +/// + #ifdef HAVE_AVX512 #define SRSRAN_SIMD_F_SIZE 16 @@ -135,25 +150,31 @@ inline bool is_simd_addr_aligned(const void* addr, uintptr_t mask) #if SRSRAN_SIMD_F_SIZE -/* Data types */ +/// +/// Data types. +/// + #ifdef HAVE_AVX512 -typedef __m512 simd_f_t; +using simd_f_t = __m512; #else /* HAVE_AVX512 */ #ifdef HAVE_AVX2 -typedef __m256 simd_f_t; +using simd_f_t = __m256; #else /* HAVE_AVX2 */ #ifdef HAVE_SSE -typedef __m128 simd_f_t; +using simd_f_t = __m128; #else /* HAVE_NEON */ #ifdef HAVE_NEON -typedef float32x4_t simd_f_t; +using simd_f_t = float32x4_t; #endif /* HAVE_NEON */ #endif /* HAVE_SSE */ #endif /* HAVE_AVX2 */ #endif /* HAVE_AVX512 */ -/* Single precision Floating point functions */ -static inline simd_f_t srsran_simd_f_load(const float* ptr) +/// +/// Single precision Floating point functions. +/// + +inline simd_f_t srsran_simd_f_load(const float* ptr) { #ifdef HAVE_AVX512 return _mm512_load_ps(ptr); @@ -172,7 +193,7 @@ static inline simd_f_t srsran_simd_f_load(const float* ptr) #endif /* HAVE_AVX512 */ } -static inline simd_f_t srsran_simd_f_loadu(const float* ptr) +inline simd_f_t srsran_simd_f_loadu(const float* ptr) { #ifdef HAVE_AVX512 return _mm512_loadu_ps(ptr); @@ -191,7 +212,7 @@ static inline simd_f_t srsran_simd_f_loadu(const float* ptr) #endif /* HAVE_AVX512 */ } -static inline void srsran_simd_f_store(float* ptr, simd_f_t simdreg) +inline void srsran_simd_f_store(float* ptr, simd_f_t simdreg) { #ifdef HAVE_AVX512 _mm512_store_ps(ptr, simdreg); @@ -210,7 +231,7 @@ static inline void srsran_simd_f_store(float* ptr, simd_f_t simdreg) #endif /* HAVE_AVX512 */ } -static inline void srsran_simd_f_storeu(float* ptr, simd_f_t simdreg) +inline void srsran_simd_f_storeu(float* ptr, simd_f_t simdreg) { #ifdef HAVE_AVX512 _mm512_storeu_ps(ptr, simdreg); @@ -229,7 +250,7 @@ static inline void srsran_simd_f_storeu(float* ptr, simd_f_t simdreg) #endif /* HAVE_AVX512 */ } -static inline simd_f_t srsran_simd_f_set1(float x) +inline simd_f_t srsran_simd_f_set1(float x) { #ifdef HAVE_AVX512 return _mm512_set1_ps(x); @@ -248,7 +269,7 @@ static inline simd_f_t srsran_simd_f_set1(float x) #endif /* HAVE_AVX512 */ } -static inline simd_f_t srsran_simd_f_mul(simd_f_t a, simd_f_t b) +inline simd_f_t srsran_simd_f_mul(simd_f_t a, simd_f_t b) { #ifdef HAVE_AVX512 return _mm512_mul_ps(a, b); @@ -267,7 +288,7 @@ static inline simd_f_t srsran_simd_f_mul(simd_f_t a, simd_f_t b) #endif /* HAVE_AVX512 */ } -static inline simd_f_t srsran_simd_f_rcp(simd_f_t a) +inline simd_f_t srsran_simd_f_rcp(simd_f_t a) { #ifdef HAVE_AVX512 return _mm512_rcp14_ps(a); @@ -286,7 +307,7 @@ static inline simd_f_t srsran_simd_f_rcp(simd_f_t a) #endif /* HAVE_AVX512 */ } -static inline simd_f_t srsran_simd_f_addsub(simd_f_t a, simd_f_t b) +inline simd_f_t srsran_simd_f_addsub(simd_f_t a, simd_f_t b) { #ifdef HAVE_AVX512 __m512 r = _mm512_add_ps(a, b); @@ -299,18 +320,17 @@ static inline simd_f_t srsran_simd_f_addsub(simd_f_t a, simd_f_t b) return _mm_addsub_ps(a, b); #else /* HAVE_SSE */ #ifdef HAVE_NEON // CURRENTLY USES GENERIC IMPLEMENTATION FOR NEON - float* a_ptr = (float*)&a; - float* b_ptr = (float*)&b; - simd_f_t ret; - float* c_ptr = (float*)&ret; - for (int i = 0; i < 4; i++) { + const float* a_ptr = reinterpret_cast(&a); + const float* b_ptr = reinterpret_cast(&b); + simd_f_t ret; + float* c_ptr = reinterpret_cast(&ret); + for (int i = 0; i != 4; ++i) { if (i % 2 == 0) { c_ptr[i] = a_ptr[i] - b_ptr[i]; } else { c_ptr[i] = a_ptr[i] + b_ptr[i]; } } - return ret; #endif /* HAVE_NEON */ #endif /* HAVE_SSE */ @@ -318,7 +338,7 @@ static inline simd_f_t srsran_simd_f_addsub(simd_f_t a, simd_f_t b) #endif /* HAVE_AVX512 */ } -static inline simd_f_t srsran_simd_f_sub(simd_f_t a, simd_f_t b) +inline simd_f_t srsran_simd_f_sub(simd_f_t a, simd_f_t b) { #ifdef HAVE_AVX512 return _mm512_sub_ps(a, b); @@ -337,7 +357,7 @@ static inline simd_f_t srsran_simd_f_sub(simd_f_t a, simd_f_t b) #endif /* HAVE_AVX512 */ } -static inline simd_f_t srsran_simd_f_add(simd_f_t a, simd_f_t b) +inline simd_f_t srsran_simd_f_add(simd_f_t a, simd_f_t b) { #ifdef HAVE_AVX512 return _mm512_add_ps(a, b); @@ -356,7 +376,7 @@ static inline simd_f_t srsran_simd_f_add(simd_f_t a, simd_f_t b) #endif /* HAVE_AVX512 */ } -static inline simd_f_t srsran_simd_f_fma(simd_f_t acc, simd_f_t a, simd_f_t b) +inline simd_f_t srsran_simd_f_fma(simd_f_t acc, simd_f_t a, simd_f_t b) { #ifdef HAVE_AVX512 return _mm512_fmadd_ps(a, b, acc); @@ -375,7 +395,7 @@ static inline simd_f_t srsran_simd_f_fma(simd_f_t acc, simd_f_t a, simd_f_t b) #endif /* HAVE_AVX512 */ } -static inline simd_f_t srsran_simd_f_zero(void) +inline simd_f_t srsran_simd_f_zero() { #ifdef HAVE_AVX512 return _mm512_setzero_ps(); @@ -394,7 +414,7 @@ static inline simd_f_t srsran_simd_f_zero(void) #endif /* HAVE_AVX512 */ } -static inline simd_f_t srsran_simd_f_swap(simd_f_t a) +inline simd_f_t srsran_simd_f_swap(simd_f_t a) { #ifdef HAVE_AVX512 return _mm512_permute_ps(a, 0b10110001); @@ -413,7 +433,7 @@ static inline simd_f_t srsran_simd_f_swap(simd_f_t a) #endif /* HAVE_AVX512 */ } -static inline simd_f_t srsran_simd_f_hadd(simd_f_t a, simd_f_t b) +inline simd_f_t srsran_simd_f_hadd(simd_f_t a, simd_f_t b) { #ifdef HAVE_AVX512 const __m512i idx1 = _mm512_setr_epi32((0b00000), @@ -454,7 +474,7 @@ static inline simd_f_t srsran_simd_f_hadd(simd_f_t a, simd_f_t b) #endif /* HAVE_AVX512 */ } -static inline simd_f_t srsran_simd_f_sqrt(simd_f_t a) +inline simd_f_t srsran_simd_f_sqrt(simd_f_t a) { #ifdef HAVE_AVX512 return _mm512_sqrt_ps(a); @@ -470,17 +490,20 @@ static inline simd_f_t srsran_simd_f_sqrt(simd_f_t a) sqrt_reciprocal = vmulq_f32(vrsqrtsq_f32(vmulq_f32(a, sqrt_reciprocal), sqrt_reciprocal), sqrt_reciprocal); float32x4_t result = vmulq_f32(a, sqrt_reciprocal); - /* Detect zeros in NEON 1/sqrtf for preventing NaN */ - float32x4_t zeros = vmovq_n_f32(0); /* Zero vector */ - uint32x4_t mask = vceqq_f32(a, zeros); /* Zero vector mask */ - return vbslq_f32(mask, zeros, result); /* Force zero results and return */ + // Detect zeros in NEON 1/sqrtf for preventing NaN. + // Zero vector. + float32x4_t zeros = vmovq_n_f32(0); + // Zero vector mask. + uint32x4_t mask = vceqq_f32(a, zeros); + // Force zero results and return. + return vbslq_f32(mask, zeros, result); #endif /* HAVE_NEON */ #endif /* HAVE_SSE */ #endif /* HAVE_AVX2 */ #endif /* HAVE_AVX512 */ } -static inline simd_f_t srsran_simd_f_neg(simd_f_t a) +inline simd_f_t srsran_simd_f_neg(simd_f_t a) { #ifdef HAVE_AVX512 return _mm512_xor_ps(_mm512_set1_ps(-0.0f), a); @@ -499,7 +522,7 @@ static inline simd_f_t srsran_simd_f_neg(simd_f_t a) #endif /* HAVE_AVX512 */ } -static inline simd_f_t srsran_simd_f_neg_mask(simd_f_t a, simd_f_t mask) +inline simd_f_t srsran_simd_f_neg_mask(simd_f_t a, simd_f_t mask) { #ifdef HAVE_AVX512 return _mm512_xor_ps(mask, a); @@ -518,7 +541,7 @@ static inline simd_f_t srsran_simd_f_neg_mask(simd_f_t a, simd_f_t mask) #endif /* HAVE_AVX512 */ } -static inline simd_f_t srsran_simd_f_abs(simd_f_t a) +inline simd_f_t srsran_simd_f_abs(simd_f_t a) { #ifdef HAVE_AVX512 return _mm512_andnot_ps(_mm512_set1_ps(-0.0f), a); @@ -537,17 +560,17 @@ static inline simd_f_t srsran_simd_f_abs(simd_f_t a) #endif /* HAVE_AVX512 */ } -static inline void srsran_simd_f_fprintf(FILE* stream, simd_f_t a) +inline void srsran_simd_f_fprintf(std::FILE* stream, simd_f_t a) { float x[SRSRAN_SIMD_F_SIZE]; srsran_simd_f_storeu(x, a); - fprintf(stream, "["); - for (int i = 0; i < SRSRAN_SIMD_F_SIZE; i++) { - fprintf(stream, "%+2.5f, ", x[i]); + std::fprintf(stream, "["); + for (float f : x) { + std::fprintf(stream, "%+2.5f, ", f); } - fprintf(stream, "];\n"); + std::fprintf(stream, "];\n"); } #endif /* SRSRAN_SIMD_F_SIZE */ @@ -555,21 +578,24 @@ static inline void srsran_simd_f_fprintf(FILE* stream, simd_f_t a) #if SRSRAN_SIMD_CF_SIZE #ifdef HAVE_NEON -typedef float32x4x2_t simd_cf_t; +using simd_cf_t = float32x4x2_t; #else -typedef struct { +struct simd_cf_t { simd_f_t re; simd_f_t im; -} simd_cf_t; +}; #endif -/* Complex Single precission Floating point functions */ -static inline simd_cf_t srsran_simd_cfi_load(const cf_t* ptr) +/// +/// Complex Single precision Floating point functions. +/// + +inline simd_cf_t srsran_simd_cfi_load(const cf_t* ptr) { simd_cf_t ret; #ifdef HAVE_AVX512 - __m512 in1 = _mm512_load_ps((float*)(ptr)); - __m512 in2 = _mm512_load_ps((float*)(ptr + SRSRAN_SIMD_CF_SIZE / 2)); + __m512 in1 = _mm512_load_ps(reinterpret_cast(ptr)); + __m512 in2 = _mm512_load_ps(reinterpret_cast(ptr + SRSRAN_SIMD_CF_SIZE / 2)); ret.re = _mm512_permutex2var_ps( in1, _mm512_setr_epi32(0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e), @@ -580,19 +606,19 @@ static inline simd_cf_t srsran_simd_cfi_load(const cf_t* ptr) in2); #else /* HAVE_AVX512 */ #ifdef HAVE_AVX2 - __m256 in1 = _mm256_permute_ps(_mm256_load_ps((float*)(ptr)), 0b11011000); - __m256 in2 = _mm256_permute_ps(_mm256_load_ps((float*)(ptr + 4)), 0b11011000); + __m256 in1 = _mm256_permute_ps(_mm256_load_ps(reinterpret_cast(ptr)), 0b11011000); + __m256 in2 = _mm256_permute_ps(_mm256_load_ps(reinterpret_cast(ptr + 4)), 0b11011000); ret.re = _mm256_unpacklo_ps(in1, in2); ret.im = _mm256_unpackhi_ps(in1, in2); #else /* HAVE_AVX2 */ #ifdef HAVE_SSE - __m128 i1 = _mm_load_ps((float*)(ptr)); - __m128 i2 = _mm_load_ps((float*)(ptr + 2)); + __m128 i1 = _mm_load_ps(reinterpret_cast(ptr)); + __m128 i2 = _mm_load_ps(reinterpret_cast(ptr + 2)); ret.re = _mm_shuffle_ps(i1, i2, _MM_SHUFFLE(2, 0, 2, 0)); ret.im = _mm_shuffle_ps(i1, i2, _MM_SHUFFLE(3, 1, 3, 1)); #else #ifdef HAVE_NEON - ret = vld2q_f32((float*)(ptr)); + ret = vld2q_f32(reinterpret_cast(ptr)); #endif /* HAVE_NEON */ #endif /* HAVE_SSE */ #endif /* HAVE_AVX2 */ @@ -600,13 +626,12 @@ static inline simd_cf_t srsran_simd_cfi_load(const cf_t* ptr) return ret; } -/* Complex Single precission Floating point functions */ -static inline simd_cf_t srsran_simd_cfi_loadu(const cf_t* ptr) +inline simd_cf_t srsran_simd_cfi_loadu(const cf_t* ptr) { simd_cf_t ret; #ifdef HAVE_AVX512 - __m512 in1 = _mm512_loadu_ps((float*)(ptr)); - __m512 in2 = _mm512_loadu_ps((float*)(ptr + SRSRAN_SIMD_CF_SIZE / 2)); + __m512 in1 = _mm512_loadu_ps(reinterpret_cast(ptr)); + __m512 in2 = _mm512_loadu_ps(reinterpret_cast(ptr + SRSRAN_SIMD_CF_SIZE / 2)); ret.re = _mm512_permutex2var_ps( in1, _mm512_setr_epi32(0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e), @@ -617,19 +642,19 @@ static inline simd_cf_t srsran_simd_cfi_loadu(const cf_t* ptr) in2); #else /* HAVE_AVX512 */ #ifdef HAVE_AVX2 - __m256 in1 = _mm256_permute_ps(_mm256_loadu_ps((float*)(ptr)), 0b11011000); - __m256 in2 = _mm256_permute_ps(_mm256_loadu_ps((float*)(ptr + 4)), 0b11011000); + __m256 in1 = _mm256_permute_ps(_mm256_loadu_ps(reinterpret_cast(ptr)), 0b11011000); + __m256 in2 = _mm256_permute_ps(_mm256_loadu_ps(reinterpret_cast(ptr + 4)), 0b11011000); ret.re = _mm256_unpacklo_ps(in1, in2); ret.im = _mm256_unpackhi_ps(in1, in2); #else /* HAVE_AVX2 */ #ifdef HAVE_SSE - __m128 i1 = _mm_loadu_ps((float*)(ptr)); - __m128 i2 = _mm_loadu_ps((float*)(ptr + 2)); + __m128 i1 = _mm_loadu_ps(reinterpret_cast(ptr)); + __m128 i2 = _mm_loadu_ps(reinterpret_cast(ptr + 2)); ret.re = _mm_shuffle_ps(i1, i2, _MM_SHUFFLE(2, 0, 2, 0)); ret.im = _mm_shuffle_ps(i1, i2, _MM_SHUFFLE(3, 1, 3, 1)); #else #ifdef HAVE_NEON - ret = vld2q_f32((float*)(ptr)); + ret = vld2q_f32(reinterpret_cast(ptr)); #endif /* HAVE_NEON */ #endif /* HAVE_SSE */ #endif /* HAVE_AVX2 */ @@ -637,7 +662,7 @@ static inline simd_cf_t srsran_simd_cfi_loadu(const cf_t* ptr) return ret; } -static inline simd_cf_t srsran_simd_cf_load(const float* re, const float* im) +inline simd_cf_t srsran_simd_cf_load(const float* re, const float* im) { simd_cf_t ret; #ifdef HAVE_AVX512 @@ -651,7 +676,7 @@ static inline simd_cf_t srsran_simd_cf_load(const float* re, const float* im) #ifdef HAVE_SSE ret.re = _mm_load_ps(re); ret.im = _mm_load_ps(im); -#else /*HAVE_NEON*/ +#else /* HAVE_NEON */ #ifdef HAVE_NEON ret.val[0] = vld1q_f32(re); ret.val[1] = vld1q_f32(im); @@ -662,7 +687,7 @@ static inline simd_cf_t srsran_simd_cf_load(const float* re, const float* im) return ret; } -static inline simd_cf_t srsran_simd_cf_loadu(const float* re, const float* im) +inline simd_cf_t srsran_simd_cf_loadu(const float* re, const float* im) { simd_cf_t ret; #ifdef HAVE_AVX512 @@ -676,7 +701,7 @@ static inline simd_cf_t srsran_simd_cf_loadu(const float* re, const float* im) #ifdef HAVE_SSE ret.re = _mm_loadu_ps(re); ret.im = _mm_loadu_ps(im); -#else /*HAVE_NEON*/ +#else /* HAVE_NEON */ #ifdef HAVE_NEON ret.val[0] = vld1q_f32(re); ret.val[1] = vld1q_f32(im); @@ -687,7 +712,7 @@ static inline simd_cf_t srsran_simd_cf_loadu(const float* re, const float* im) return ret; } -static inline void srsran_simd_cfi_store(cf_t* ptr, simd_cf_t simdreg) +inline void srsran_simd_cfi_store(cf_t* ptr, simd_cf_t simdreg) { #ifdef HAVE_AVX512 __m512 s1 = _mm512_permutex2var_ps( @@ -698,28 +723,28 @@ static inline void srsran_simd_cfi_store(cf_t* ptr, simd_cf_t simdreg) simdreg.re, _mm512_setr_epi32(0x08, 0x18, 0x09, 0x19, 0x0a, 0x1a, 0x0b, 0x1b, 0x0c, 0x1c, 0x0d, 0x1d, 0x0e, 0x1e, 0x0f, 0x1f), simdreg.im); - _mm512_store_ps((float*)(ptr), s1); - _mm512_store_ps((float*)(ptr + 8), s2); + _mm512_store_ps(reinterpret_cast(ptr), s1); + _mm512_store_ps(reinterpret_cast(ptr + 8), s2); #else /* HAVE_AVX512 */ #ifdef HAVE_AVX2 __m256 out1 = _mm256_permute_ps(simdreg.re, 0b11011000); __m256 out2 = _mm256_permute_ps(simdreg.im, 0b11011000); - _mm256_store_ps((float*)(ptr), _mm256_unpacklo_ps(out1, out2)); - _mm256_store_ps((float*)(ptr + 4), _mm256_unpackhi_ps(out1, out2)); + _mm256_store_ps(reinterpret_cast(ptr), _mm256_unpacklo_ps(out1, out2)); + _mm256_store_ps(reinterpret_cast(ptr + 4), _mm256_unpackhi_ps(out1, out2)); #else /* HAVE_AVX2 */ #ifdef HAVE_SSE - _mm_store_ps((float*)(ptr), _mm_unpacklo_ps(simdreg.re, simdreg.im)); - _mm_store_ps((float*)(ptr + 2), _mm_unpackhi_ps(simdreg.re, simdreg.im)); -#else /*HAVE_NEON*/ + _mm_store_ps(reinterpret_cast(ptr), _mm_unpacklo_ps(simdreg.re, simdreg.im)); + _mm_store_ps(reinterpret_cast(ptr + 2), _mm_unpackhi_ps(simdreg.re, simdreg.im)); +#else /* HAVE_NEON */ #ifdef HAVE_NEON - vst2q_f32((float*)(ptr), simdreg); + vst2q_f32(reinterpret_cast(ptr), simdreg); #endif /* HAVE_NEON */ #endif /* HAVE_SSE */ #endif /* HAVE_AVX2 */ #endif /* HAVE_AVX512 */ } -static inline void srsran_simd_cfi_storeu(cf_t* ptr, simd_cf_t simdreg) +inline void srsran_simd_cfi_storeu(cf_t* ptr, simd_cf_t simdreg) { #ifdef HAVE_AVX512 __m512 s1 = _mm512_permutex2var_ps( @@ -730,28 +755,28 @@ static inline void srsran_simd_cfi_storeu(cf_t* ptr, simd_cf_t simdreg) simdreg.re, _mm512_setr_epi32(0x08, 0x18, 0x09, 0x19, 0x0a, 0x1a, 0x0b, 0x1b, 0x0c, 0x1c, 0x0d, 0x1d, 0x0e, 0x1e, 0x0f, 0x1f), simdreg.im); - _mm512_storeu_ps((float*)(ptr), s1); - _mm512_storeu_ps((float*)(ptr + 8), s2); + _mm512_storeu_ps(reinterpret_cast(ptr), s1); + _mm512_storeu_ps(reinterpret_cast(ptr + 8), s2); #else /* HAVE_AVX512 */ #ifdef HAVE_AVX2 __m256 out1 = _mm256_permute_ps(simdreg.re, 0b11011000); __m256 out2 = _mm256_permute_ps(simdreg.im, 0b11011000); - _mm256_storeu_ps((float*)(ptr), _mm256_unpacklo_ps(out1, out2)); - _mm256_storeu_ps((float*)(ptr + 4), _mm256_unpackhi_ps(out1, out2)); + _mm256_storeu_ps(reinterpret_cast(ptr), _mm256_unpacklo_ps(out1, out2)); + _mm256_storeu_ps(reinterpret_cast(ptr + 4), _mm256_unpackhi_ps(out1, out2)); #else /* HAVE_AVX2 */ #ifdef HAVE_SSE - _mm_storeu_ps((float*)(ptr), _mm_unpacklo_ps(simdreg.re, simdreg.im)); - _mm_storeu_ps((float*)(ptr + 2), _mm_unpackhi_ps(simdreg.re, simdreg.im)); -#else /*HAVE_NEON*/ + _mm_storeu_ps(reinterpret_cast(ptr), _mm_unpacklo_ps(simdreg.re, simdreg.im)); + _mm_storeu_ps(reinterpret_cast(ptr + 2), _mm_unpackhi_ps(simdreg.re, simdreg.im)); +#else /* HAVE_NEON */ #ifdef HAVE_NEON - vst2q_f32((float*)(ptr), simdreg); + vst2q_f32(reinterpret_cast(ptr), simdreg); #endif /* HAVE_NEON */ #endif /* HAVE_SSE */ #endif /* HAVE_AVX2 */ #endif /* HAVE_AVX512 */ } -static inline void srsran_simd_cf_store(float* re, float* im, simd_cf_t simdreg) +inline void srsran_simd_cf_store(float* re, float* im, simd_cf_t simdreg) { #ifdef HAVE_AVX512 _mm512_store_ps(re, simdreg.re); @@ -762,19 +787,19 @@ static inline void srsran_simd_cf_store(float* re, float* im, simd_cf_t simdreg) _mm256_store_ps(im, simdreg.im); #else /* HAVE_AVX512 */ #ifdef HAVE_SSE - _mm_store_ps((float*)re, simdreg.re); - _mm_store_ps((float*)im, simdreg.im); -#else /*HAVE_NEON*/ + _mm_store_ps(re, simdreg.re); + _mm_store_ps(im, simdreg.im); +#else /* HAVE_NEON */ #ifdef HAVE_NEON - vst1q_f32((float*)re, simdreg.val[0]); - vst1q_f32((float*)im, simdreg.val[1]); + vst1q_f32(re, simdreg.val[0]); + vst1q_f32(im, simdreg.val[1]); #endif /* HAVE_NEON */ #endif /* HAVE_SSE */ #endif /* HAVE_AVX2 */ #endif /* HAVE_AVX512 */ } -static inline void srsran_simd_cf_storeu(float* re, float* im, simd_cf_t simdreg) +inline void srsran_simd_cf_storeu(float* re, float* im, simd_cf_t simdreg) { #ifdef HAVE_AVX512 _mm512_storeu_ps(re, simdreg.re); @@ -785,28 +810,28 @@ static inline void srsran_simd_cf_storeu(float* re, float* im, simd_cf_t simdreg _mm256_storeu_ps(im, simdreg.im); #else /* HAVE_AVX512 */ #ifdef HAVE_SSE - _mm_storeu_ps((float*)re, simdreg.re); - _mm_storeu_ps((float*)im, simdreg.im); -#else /*HAVE_NEON*/ + _mm_storeu_ps(re, simdreg.re); + _mm_storeu_ps(im, simdreg.im); +#else /* HAVE_NEON */ #ifdef HAVE_NEON - vst1q_f32((float*)re, simdreg.val[0]); - vst1q_f32((float*)im, simdreg.val[1]); + vst1q_f32(re, simdreg.val[0]); + vst1q_f32(im, simdreg.val[1]); #endif /* HAVE_NEON */ #endif /* HAVE_SSE */ #endif /* HAVE_AVX2 */ #endif /* HAVE_AVX512 */ } -static inline simd_f_t srsran_simd_cf_re(simd_cf_t in) +inline simd_f_t srsran_simd_cf_re(simd_cf_t in) { #ifdef HAVE_NEON simd_f_t out = in.val[0]; #else simd_f_t out = in.re; -#endif /*HAVE_NEON*/ +#endif /* HAVE_NEON */ #ifndef HAVE_AVX512 #ifdef HAVE_AVX2 - /* Permute for AVX registers (mis SSE registers) */ + // Permute for AVX registers (miss SSE registers). const __m256i idx = _mm256_setr_epi32(0, 2, 4, 6, 1, 3, 5, 7); out = _mm256_permutevar8x32_ps(out, idx); #endif /* HAVE_AVX2 */ @@ -814,16 +839,16 @@ static inline simd_f_t srsran_simd_cf_re(simd_cf_t in) return out; } -static inline simd_f_t srsran_simd_cf_im(simd_cf_t in) +inline simd_f_t srsran_simd_cf_im(simd_cf_t in) { #ifdef HAVE_NEON simd_f_t out = in.val[1]; #else simd_f_t out = in.im; -#endif /*HAVE_NEON*/ +#endif /* HAVE_NEON */ #ifndef HAVE_AVX512 #ifdef HAVE_AVX2 - /* Permute for AVX registers (mis SSE registers) */ + // Permute for AVX registers (miss SSE registers). const __m256i idx = _mm256_setr_epi32(0, 2, 4, 6, 1, 3, 5, 7); out = _mm256_permutevar8x32_ps(out, idx); #endif /* HAVE_AVX2 */ @@ -831,7 +856,7 @@ static inline simd_f_t srsran_simd_cf_im(simd_cf_t in) return out; } -static inline simd_cf_t srsran_simd_cf_set1(cf_t x) +inline simd_cf_t srsran_simd_cf_set1(cf_t x) { simd_cf_t ret; #ifdef HAVE_AVX512 @@ -845,7 +870,7 @@ static inline simd_cf_t srsran_simd_cf_set1(cf_t x) #ifdef HAVE_SSE ret.re = _mm_set1_ps(x.real()); ret.im = _mm_set1_ps(x.imag()); -#else /*HAVE_NEON*/ +#else /* HAVE_NEON */ #ifdef HAVE_NEON ret.val[0] = vdupq_n_f32(x.real()); ret.val[1] = vdupq_n_f32(x.imag()); @@ -856,7 +881,7 @@ static inline simd_cf_t srsran_simd_cf_set1(cf_t x) return ret; } -static inline simd_cf_t srsran_simd_cf_prod(simd_cf_t a, simd_cf_t b) +inline simd_cf_t srsran_simd_cf_prod(simd_cf_t a, simd_cf_t b) { simd_cf_t ret; #ifdef HAVE_AVX512 @@ -886,7 +911,7 @@ static inline simd_cf_t srsran_simd_cf_prod(simd_cf_t a, simd_cf_t b) return ret; } -static inline simd_cf_t srsran_simd_cf_conjprod(simd_cf_t a, simd_cf_t b) +inline simd_cf_t srsran_simd_cf_conjprod(simd_cf_t a, simd_cf_t b) { simd_cf_t ret; #ifdef HAVE_AVX512 @@ -911,7 +936,7 @@ static inline simd_cf_t srsran_simd_cf_conjprod(simd_cf_t a, simd_cf_t b) return ret; } -static inline simd_cf_t srsran_simd_cf_add(simd_cf_t a, simd_cf_t b) +inline simd_cf_t srsran_simd_cf_add(simd_cf_t a, simd_cf_t b) { simd_cf_t ret; #ifdef HAVE_AVX512 @@ -936,7 +961,7 @@ static inline simd_cf_t srsran_simd_cf_add(simd_cf_t a, simd_cf_t b) return ret; } -static inline simd_cf_t srsran_simd_cf_sub(simd_cf_t a, simd_cf_t b) +inline simd_cf_t srsran_simd_cf_sub(simd_cf_t a, simd_cf_t b) { simd_cf_t ret; #ifdef HAVE_AVX512 @@ -961,13 +986,13 @@ static inline simd_cf_t srsran_simd_cf_sub(simd_cf_t a, simd_cf_t b) return ret; } -static inline simd_f_t srsran_simd_cf_norm_sq(simd_cf_t a) +inline simd_f_t srsran_simd_cf_norm_sq(simd_cf_t a) { return srsran_simd_f_fma( srsran_simd_f_mul(srsran_simd_cf_re(a), srsran_simd_cf_re(a)), srsran_simd_cf_im(a), srsran_simd_cf_im(a)); } -static inline simd_cf_t srsran_simd_cf_mul(simd_cf_t a, simd_f_t b) +inline simd_cf_t srsran_simd_cf_mul(simd_cf_t a, simd_f_t b) { simd_cf_t ret; #ifdef HAVE_AVX512 @@ -993,7 +1018,7 @@ static inline simd_cf_t srsran_simd_cf_mul(simd_cf_t a, simd_f_t b) return ret; } -static inline simd_cf_t srsran_simd_cf_rcp(simd_cf_t a) +inline simd_cf_t srsran_simd_cf_rcp(simd_cf_t a) { simd_cf_t ret; #ifdef HAVE_AVX512 @@ -1038,7 +1063,7 @@ static inline simd_cf_t srsran_simd_cf_rcp(simd_cf_t a) return ret; } -static inline simd_cf_t srsran_simd_cf_neg(simd_cf_t a) +inline simd_cf_t srsran_simd_cf_neg(simd_cf_t a) { simd_cf_t ret; #if HAVE_NEON @@ -1051,7 +1076,7 @@ static inline simd_cf_t srsran_simd_cf_neg(simd_cf_t a) return ret; } -static inline simd_cf_t srsran_simd_cf_neg_mask(simd_cf_t a, simd_f_t mask) +inline simd_cf_t srsran_simd_cf_neg_mask(simd_cf_t a, simd_f_t mask) { simd_cf_t ret; #ifndef HAVE_AVX512 @@ -1069,7 +1094,7 @@ static inline simd_cf_t srsran_simd_cf_neg_mask(simd_cf_t a, simd_f_t mask) return ret; } -static inline simd_cf_t srsran_simd_cf_conj(simd_cf_t a) +inline simd_cf_t srsran_simd_cf_conj(simd_cf_t a) { simd_cf_t ret; #if HAVE_NEON @@ -1082,7 +1107,7 @@ static inline simd_cf_t srsran_simd_cf_conj(simd_cf_t a) return ret; } -static inline simd_cf_t srsran_simd_cf_mulj(simd_cf_t a) +inline simd_cf_t srsran_simd_cf_mulj(simd_cf_t a) { simd_cf_t ret; #if HAVE_NEON @@ -1095,7 +1120,7 @@ static inline simd_cf_t srsran_simd_cf_mulj(simd_cf_t a) return ret; } -static inline simd_cf_t srsran_simd_cf_zero(void) +inline simd_cf_t srsran_simd_cf_zero() { simd_cf_t ret; #ifdef HAVE_AVX512 @@ -1120,17 +1145,17 @@ static inline simd_cf_t srsran_simd_cf_zero(void) return ret; } -static inline void srsran_simd_cf_fprintf(FILE* stream, simd_cf_t a) +inline void srsran_simd_cf_fprintf(std::FILE* stream, simd_cf_t a) { cf_t x[SRSRAN_SIMD_CF_SIZE]; srsran_simd_cfi_storeu(x, a); - fprintf(stream, "["); - for (int i = 0; i < SRSRAN_SIMD_CF_SIZE; i++) { - fprintf(stream, "%+2.5f%+2.5fi, ", x[i].real(), x[i].imag()); + std::fprintf(stream, "["); + for (auto c : x) { + std::fprintf(stream, "%+2.5f%+2.5fi, ", c.real(), c.imag()); } - fprintf(stream, "];\n"); + std::fprintf(stream, "];\n"); } #endif /* SRSRAN_SIMD_CF_SIZE */ @@ -1138,64 +1163,64 @@ static inline void srsran_simd_cf_fprintf(FILE* stream, simd_cf_t a) #if SRSRAN_SIMD_I_SIZE #ifdef HAVE_AVX512 -typedef __m512i simd_i_t; -typedef __mmask16 simd_sel_t; +using simd_i_t = __m512i; +using simd_sel_t = __mmask16; #else /* HAVE_AVX512 */ #ifdef HAVE_AVX2 -typedef __m256i simd_i_t; -typedef __m256 simd_sel_t; +using simd_i_t = __m256i; +using simd_sel_t = __m256; #else /* HAVE_AVX2 */ #ifdef HAVE_SSE -typedef __m128i simd_i_t; -typedef __m128 simd_sel_t; +using simd_i_t = __m128i; +using simd_sel_t = __m128; #else /* HAVE_AVX2 */ #ifdef HAVE_NEON -typedef int32x4_t simd_i_t; -typedef uint32x4_t simd_sel_t; +using simd_i_t = int32x4_t; +using simd_sel_t = uint32x4_t; #endif /* HAVE_NEON */ #endif /* HAVE_SSE */ #endif /* HAVE_AVX2 */ #endif /* HAVE_AVX512 */ -static inline simd_i_t srsran_simd_i_load(int32_t* x) +inline simd_i_t srsran_simd_i_load(const int32_t* x) { #ifdef HAVE_AVX512 - return _mm512_load_epi32((__m512i*)x); + return _mm512_load_epi32(reinterpret_cast(x)); #else /* HAVE_AVX512 */ #ifdef HAVE_AVX2 - return _mm256_load_si256((__m256i*)x); + return _mm256_load_si256(reinterpret_cast(x)); #else #ifdef HAVE_SSE - return _mm_load_si128((__m128i*)x); + return _mm_load_si128(reinterpret_cast(x)); #else #ifdef HAVE_NEON - return vld1q_s32((int*)x); + return vld1q_s32(reinterpret_cast(x)); #endif /* HAVE_NEON */ #endif /* HAVE_SSE */ #endif /* HAVE_AVX2 */ #endif /* HAVE_AVX512 */ } -static inline void srsran_simd_i_store(int32_t* x, simd_i_t reg) +inline void srsran_simd_i_store(int32_t* x, simd_i_t reg) { #ifdef HAVE_AVX512 - _mm512_store_epi32((__m512i*)x, reg); + _mm512_store_epi32(reinterpret_cast<__m512i*>(x), reg); #else /* HAVE_AVX512 */ #ifdef HAVE_AVX2 - _mm256_store_si256((__m256i*)x, reg); + _mm256_store_si256(reinterpret_cast<__m256i*>(x), reg); #else #ifdef HAVE_SSE - _mm_store_si128((__m128i*)x, reg); + _mm_store_si128(reinterpret_cast<__m128i*>(x), reg); #else #ifdef HAVE_NEON - vst1q_s32((int*)x, reg); -#endif /*HAVE_NEON*/ + vst1q_s32(reinterpret_cast(x), reg); +#endif /* HAVE_NEON */ #endif /* HAVE_SSE */ #endif /* HAVE_AVX2 */ #endif /* HAVE_AVX512 */ } -static inline simd_i_t srsran_simd_i_set1(int x) +inline simd_i_t srsran_simd_i_set1(int x) { #ifdef HAVE_AVX512 return _mm512_set1_epi32(x); @@ -1214,7 +1239,7 @@ static inline simd_i_t srsran_simd_i_set1(int x) #endif /* HAVE_AVX512 */ } -static inline simd_i_t srsran_simd_i_add(simd_i_t a, simd_i_t b) +inline simd_i_t srsran_simd_i_add(simd_i_t a, simd_i_t b) { #ifdef HAVE_AVX512 return _mm512_add_epi32(a, b); @@ -1233,7 +1258,7 @@ static inline simd_i_t srsran_simd_i_add(simd_i_t a, simd_i_t b) #endif /* HAVE_AVX512 */ } -static inline simd_i_t srsran_simd_i_mul(simd_i_t a, simd_i_t b) +inline simd_i_t srsran_simd_i_mul(simd_i_t a, simd_i_t b) { #ifdef HAVE_AVX512 return _mm512_mullo_epi32(a, b); @@ -1252,7 +1277,7 @@ static inline simd_i_t srsran_simd_i_mul(simd_i_t a, simd_i_t b) #endif /* HAVE_AVX512 */ } -static inline simd_i_t srsran_simd_i_and(simd_i_t a, simd_i_t b) +inline simd_i_t srsran_simd_i_and(simd_i_t a, simd_i_t b) { #ifdef HAVE_AVX512 return _mm512_and_si512(a, b); @@ -1271,7 +1296,7 @@ static inline simd_i_t srsran_simd_i_and(simd_i_t a, simd_i_t b) #endif /* HAVE_AVX512 */ } -static inline simd_sel_t srsran_simd_sel_and(simd_sel_t a, simd_sel_t b) +inline simd_sel_t srsran_simd_sel_and(simd_sel_t a, simd_sel_t b) { #ifdef HAVE_AVX512 return _kand_mask16(a, b); @@ -1290,7 +1315,7 @@ static inline simd_sel_t srsran_simd_sel_and(simd_sel_t a, simd_sel_t b) #endif /* HAVE_AVX512 */ } -static inline simd_sel_t srsran_simd_f_max(simd_f_t a, simd_f_t b) +inline simd_sel_t srsran_simd_f_max(simd_f_t a, simd_f_t b) { #ifdef HAVE_AVX512 return _mm512_cmp_ps_mask(a, b, _CMP_GT_OS); @@ -1309,7 +1334,7 @@ static inline simd_sel_t srsran_simd_f_max(simd_f_t a, simd_f_t b) #endif /* HAVE_AVX512 */ } -static inline simd_sel_t srsran_simd_f_min(simd_f_t a, simd_f_t b) +inline simd_sel_t srsran_simd_f_min(simd_f_t a, simd_f_t b) { #ifdef HAVE_AVX512 return _mm512_cmp_ps_mask(a, b, _CMP_LT_OS); @@ -1328,7 +1353,7 @@ static inline simd_sel_t srsran_simd_f_min(simd_f_t a, simd_f_t b) #endif /* HAVE_AVX512 */ } -static inline simd_f_t srsran_simd_f_select(simd_f_t a, simd_f_t b, simd_sel_t selector) +inline simd_f_t srsran_simd_f_select(simd_f_t a, simd_f_t b, simd_sel_t selector) { #ifdef HAVE_AVX512 return _mm512_mask_blend_ps(selector, (__m512)a, (__m512)b); @@ -1347,7 +1372,7 @@ static inline simd_f_t srsran_simd_f_select(simd_f_t a, simd_f_t b, simd_sel_t s #endif /* HAVE_AVX512 */ } -static inline simd_cf_t srsran_simd_cf_select(simd_cf_t a, simd_cf_t b, simd_sel_t selector) +inline simd_cf_t srsran_simd_cf_select(simd_cf_t a, simd_cf_t b, simd_sel_t selector) { simd_cf_t ret; #ifdef HAVE_AVX512 @@ -1374,7 +1399,7 @@ static inline simd_cf_t srsran_simd_cf_select(simd_cf_t a, simd_cf_t b, simd_sel return ret; } -static inline simd_i_t srsran_simd_i_select(simd_i_t a, simd_i_t b, simd_sel_t selector) +inline simd_i_t srsran_simd_i_select(simd_i_t a, simd_i_t b, simd_sel_t selector) { #ifdef HAVE_AVX512 return (__m512i)_mm512_mask_blend_ps(selector, (__m512)a, (__m512)b); @@ -1393,36 +1418,36 @@ static inline simd_i_t srsran_simd_i_select(simd_i_t a, simd_i_t b, simd_sel_t s #endif /* HAVE_AVX512 */ } -#endif /* SRSRAN_SIMD_I_SIZE*/ +#endif /* SRSRAN_SIMD_I_SIZE */ #if SRSRAN_SIMD_S_SIZE #ifdef HAVE_AVX512 -typedef __m512i simd_s_t; +using simd_s_t = __m512i; #else /* HAVE_AVX512 */ #ifdef HAVE_AVX2 -typedef __m256i simd_s_t; +using simd_s_t = __m256i; #else /* HAVE_AVX2 */ #ifdef HAVE_SSE -typedef __m128i simd_s_t; +using simd_s_t = __m128i; #else /* HAVE_SSE */ #ifdef HAVE_NEON -typedef int16x8_t simd_s_t; +using simd_s_t = int16x8_t; #endif /* HAVE_NEON */ #endif /* HAVE_SSE */ #endif /* HAVE_AVX2 */ #endif /* HAVE_AVX512 */ -static inline simd_s_t srsran_simd_s_load(const int16_t* ptr) +inline simd_s_t srsran_simd_s_load(const int16_t* ptr) { #ifdef HAVE_AVX512 return _mm512_load_si512(ptr); #else /* HAVE_AVX512 */ #ifdef HAVE_AVX2 - return _mm256_load_si256((__m256i*)ptr); + return _mm256_load_si256(reinterpret_cast(ptr)); #else /* HAVE_AVX2 */ #ifdef HAVE_SSE - return _mm_load_si128((__m128i*)ptr); + return _mm_load_si128(reinterpret_cast(ptr)); #else /* HAVE_SSE */ #ifdef HAVE_NEON return vld1q_s16(ptr); @@ -1432,16 +1457,16 @@ static inline simd_s_t srsran_simd_s_load(const int16_t* ptr) #endif /* HAVE_AVX512 */ } -static inline simd_s_t srsran_simd_s_loadu(const int16_t* ptr) +inline simd_s_t srsran_simd_s_loadu(const int16_t* ptr) { #ifdef HAVE_AVX512 return _mm512_loadu_si512(ptr); #else /* HAVE_AVX512 */ #ifdef HAVE_AVX2 - return _mm256_loadu_si256((__m256i*)ptr); + return _mm256_loadu_si256(reinterpret_cast(ptr)); #else /* HAVE_AVX2 */ #ifdef HAVE_SSE - return _mm_loadu_si128((__m128i*)ptr); + return _mm_loadu_si128(reinterpret_cast(ptr)); #else /* HAVE_SSE */ #ifdef HAVE_NEON return vld1q_s16(ptr); @@ -1451,16 +1476,16 @@ static inline simd_s_t srsran_simd_s_loadu(const int16_t* ptr) #endif /* HAVE_AVX512 */ } -static inline void srsran_simd_s_store(int16_t* ptr, simd_s_t simdreg) +inline void srsran_simd_s_store(int16_t* ptr, simd_s_t simdreg) { #ifdef HAVE_AVX512 _mm512_store_si512(ptr, simdreg); #else /* HAVE_AVX512 */ #ifdef HAVE_AVX2 - _mm256_store_si256((__m256i*)ptr, simdreg); + _mm256_store_si256(reinterpret_cast<__m256i*>(ptr), simdreg); #else /* HAVE_AVX2 */ #ifdef HAVE_SSE - _mm_store_si128((__m128i*)ptr, simdreg); + _mm_store_si128(reinterpret_cast<__m128i*>(ptr), simdreg); #else /* HAVE_SSE */ #ifdef HAVE_NEON vst1q_s16(ptr, simdreg); @@ -1470,16 +1495,16 @@ static inline void srsran_simd_s_store(int16_t* ptr, simd_s_t simdreg) #endif /* HAVE_AVX512 */ } -static inline void srsran_simd_s_storeu(int16_t* ptr, simd_s_t simdreg) +inline void srsran_simd_s_storeu(int16_t* ptr, simd_s_t simdreg) { #ifdef HAVE_AVX512 _mm512_storeu_si512(ptr, simdreg); #else /* HAVE_AVX512 */ #ifdef HAVE_AVX2 - _mm256_storeu_si256((__m256i*)ptr, simdreg); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(ptr), simdreg); #else /* HAVE_AVX2 */ #ifdef HAVE_SSE - _mm_storeu_si128((__m128i*)ptr, simdreg); + _mm_storeu_si128(reinterpret_cast<__m128i*>(ptr), simdreg); #else /* HAVE_SSE */ #ifdef HAVE_NEON vst1q_s16(ptr, simdreg); @@ -1488,7 +1513,7 @@ static inline void srsran_simd_s_storeu(int16_t* ptr, simd_s_t simdreg) #endif /* HAVE_AVX2 */ #endif /* HAVE_AVX512 */ } -static inline simd_s_t srsran_simd_s_zero(void) +inline simd_s_t srsran_simd_s_zero() { #ifdef HAVE_AVX512 return _mm512_setzero_si512(); @@ -1507,7 +1532,7 @@ static inline simd_s_t srsran_simd_s_zero(void) #endif /* HAVE_AVX512 */ } -static inline simd_s_t srsran_simd_s_mul(simd_s_t a, simd_s_t b) +inline simd_s_t srsran_simd_s_mul(simd_s_t a, simd_s_t b) { #ifdef HAVE_AVX512 return _mm512_mullo_epi16(a, b); @@ -1526,7 +1551,7 @@ static inline simd_s_t srsran_simd_s_mul(simd_s_t a, simd_s_t b) #endif /* HAVE_AVX512 */ } -static inline simd_s_t srsran_simd_s_neg(simd_s_t a, simd_s_t b) +inline simd_s_t srsran_simd_s_neg(simd_s_t a, simd_s_t b) { #ifdef HAVE_AVX512 __m256i a0 = _mm512_extracti64x4_epi64(a, 0); @@ -1544,18 +1569,17 @@ static inline simd_s_t srsran_simd_s_neg(simd_s_t a, simd_s_t b) return _mm_sign_epi16(a, b); #else /* HAVE_SSE */ #ifdef HAVE_NEON - /* Taken and modified from sse2neon.h licensed under MIT - * Source: https://github.com/DLTcollab/sse2neon - */ + // Taken and modified from sse2neon.h licensed under MIT. + // Source: https://github.com/DLTcollab/sse2neon int16x8_t zero = vdupq_n_s16(0); - // signed shift right: faster than vclt + // Signed shift right: faster than vclt. // (b < 0) ? 0xffff : 0 uint16x8_t ltMask = vreinterpretq_u16_s16(vshrq_n_s16(b, 15)); // (b == 0) ? 0xffff : 0 int16x8_t zeroMask = vreinterpretq_s16_u16(vceqq_s16(b, zero)); // -a int16x8_t neg = vnegq_s16(a); - // bitwise select either a or neg based on ltMask + // Bitwise select either a or neg based on ltMask. int16x8_t masked = vbslq_s16(ltMask, neg, a); // res = masked & (~zeroMask) int16x8_t res = vbicq_s16(masked, zeroMask); @@ -1566,7 +1590,7 @@ static inline simd_s_t srsran_simd_s_neg(simd_s_t a, simd_s_t b) #endif /* HAVE_AVX512 */ } -static inline simd_s_t srsran_simd_s_add(simd_s_t a, simd_s_t b) +inline simd_s_t srsran_simd_s_add(simd_s_t a, simd_s_t b) { #ifdef HAVE_AVX512 return _mm512_add_epi16(a, b); @@ -1585,7 +1609,7 @@ static inline simd_s_t srsran_simd_s_add(simd_s_t a, simd_s_t b) #endif /* HAVE_AVX512 */ } -static inline simd_s_t srsran_simd_s_sub(simd_s_t a, simd_s_t b) +inline simd_s_t srsran_simd_s_sub(simd_s_t a, simd_s_t b) { #ifdef HAVE_AVX512 return _mm512_sub_epi16(a, b); @@ -1608,9 +1632,8 @@ static inline simd_s_t srsran_simd_s_sub(simd_s_t a, simd_s_t b) #if SRSRAN_SIMD_C16_SIZE -typedef #ifdef HAVE_AVX512 - struct { +struct simd_c16_t { union { __m512i m512; int16_t i16[32]; @@ -1619,9 +1642,10 @@ typedef __m512i m512; int16_t i16[32]; } im; +}; #else /* HAVE_AVX512 */ #ifdef HAVE_AVX2 - struct { +struct simd_c16_t { union { __m256i m256; int16_t i16[16]; @@ -1630,9 +1654,10 @@ typedef __m256i m256; int16_t i16[16]; } im; +}; #else #ifdef HAVE_SSE - struct { +struct simd_c16_t { union { __m128i m128; int16_t i16[8]; @@ -1641,45 +1666,49 @@ typedef __m128i m128; int16_t i16[8]; } im; +}; #else #ifdef HAVE_NEON - union { +union simd_c16_t { int16x8x2_t m128; int16_t i16[16]; +}; #endif /* HAVE_NEON */ #endif /* HAVE_SSE */ #endif /* HAVE_AVX2 */ #endif /* HAVE_AVX512 */ -} simd_c16_t; -/* Fixed point precision (16-bit) functions */ -static inline simd_c16_t srsran_simd_c16i_load(const c16_t* ptr) +/// +/// Fixed point precision (16-bit) functions. +/// + +inline simd_c16_t srsran_simd_c16i_load(const c16_t* ptr) { simd_c16_t ret; #ifdef HAVE_AVX512 - __m512i in1 = _mm512_load_si512((__m512i*)(ptr)); - __m512i in2 = _mm512_load_si512((__m512i*)(ptr + 8)); + __m512i in1 = _mm512_load_si512(reinterpret_cast(ptr)); + __m512i in2 = _mm512_load_si512(reinterpret_cast(ptr + 8)); ret.re.m512 = _mm512_mask_blend_epi16( 0xaaaaaaaa, in1, _mm512_shufflelo_epi16(_mm512_shufflehi_epi16(in2, 0b10100000), 0b10100000)); ret.im.m512 = _mm512_mask_blend_epi16( 0xaaaaaaaa, _mm512_shufflelo_epi16(_mm512_shufflehi_epi16(in1, 0b11110101), 0b11110101), in2); #else /* HAVE_AVX2 */ #ifdef HAVE_AVX2 - __m256i in1 = _mm256_load_si256((__m256i*)(ptr)); - __m256i in2 = _mm256_load_si256((__m256i*)(ptr + 8)); + __m256i in1 = _mm256_load_si256(reinterpret_cast(ptr)); + __m256i in2 = _mm256_load_si256(reinterpret_cast(ptr + 8)); ret.re.m256 = _mm256_blend_epi16(in1, _mm256_shufflelo_epi16(_mm256_shufflehi_epi16(in2, 0b10100000), 0b10100000), 0b10101010); ret.im.m256 = _mm256_blend_epi16(_mm256_shufflelo_epi16(_mm256_shufflehi_epi16(in1, 0b11110101), 0b11110101), in2, 0b10101010); #else /* HAVE_AVX2 */ #ifdef HAVE_SSE - __m128i in1 = _mm_load_si128((__m128i*)(ptr)); - __m128i in2 = _mm_load_si128((__m128i*)(ptr + 8)); + __m128i in1 = _mm_load_si128(reinterpret_cast(ptr)); + __m128i in2 = _mm_load_si128(reinterpret_cast(ptr + 8)); ret.re.m128 = _mm_blend_epi16(in1, _mm_shufflelo_epi16(_mm_shufflehi_epi16(in2, 0b10100000), 0b10100000), 0b10101010); ret.im.m128 = _mm_blend_epi16(_mm_shufflelo_epi16(_mm_shufflehi_epi16(in1, 0b11110101), 0b11110101), in2, 0b10101010); #else /* HAVE_SSE*/ #ifdef HAVE_NEON - ret.m128 = vld2q_s16((int16_t*)(ptr)); + ret.m128 = vld2q_s16(reinterpret_cast(ptr)); #endif /* HAVE_NEON */ #endif /* HAVE_SSE */ #endif /* HAVE_AVX2 */ @@ -1687,125 +1716,125 @@ static inline simd_c16_t srsran_simd_c16i_load(const c16_t* ptr) return ret; } -static inline simd_c16_t srsran_simd_c16_load(const int16_t* re, const int16_t* im) +inline simd_c16_t srsran_simd_c16_load(const int16_t* re, const int16_t* im) { simd_c16_t ret; #ifdef HAVE_AVX2 - ret.re.m256 = _mm256_load_si256((__m256i*)(re)); - ret.im.m256 = _mm256_load_si256((__m256i*)(im)); + ret.re.m256 = _mm256_load_si256(reinterpret_cast(re)); + ret.im.m256 = _mm256_load_si256(reinterpret_cast(im)); #else #ifdef HAVE_SSE - ret.re.m128 = _mm_load_si128((__m128i*)(re)); - ret.im.m128 = _mm_load_si128((__m128i*)(im)); + ret.re.m128 = _mm_load_si128(reinterpret_cast(re)); + ret.im.m128 = _mm_load_si128(reinterpret_cast(im)); #else /* HAVE_SSE*/ #ifdef HAVE_NEON - ret.m128.val[0] = vld1q_s16((int16_t*)(re)); - ret.m128.val[1] = vld1q_s16((int16_t*)(im)); + ret.m128.val[0] = vld1q_s16(re); + ret.m128.val[1] = vld1q_s16(im); #endif /* HAVE_NEON */ #endif /* HAVE_SSE */ #endif /* HAVE_AVX2 */ return ret; } -static inline simd_c16_t srsran_simd_c16_loadu(const int16_t* re, const int16_t* im) +inline simd_c16_t srsran_simd_c16_loadu(const int16_t* re, const int16_t* im) { simd_c16_t ret; #ifdef HAVE_AVX2 - ret.re.m256 = _mm256_loadu_si256((__m256i*)(re)); - ret.im.m256 = _mm256_loadu_si256((__m256i*)(im)); + ret.re.m256 = _mm256_loadu_si256(reinterpret_cast(re)); + ret.im.m256 = _mm256_loadu_si256(reinterpret_cast(im)); #else #ifdef HAVE_SSE - ret.re.m128 = _mm_loadu_si128((__m128i*)(re)); - ret.im.m128 = _mm_loadu_si128((__m128i*)(im)); + ret.re.m128 = _mm_loadu_si128(reinterpret_cast(re)); + ret.im.m128 = _mm_loadu_si128(reinterpret_cast(im)); #else /* HAVE_SSE*/ #ifdef HAVE_NEON - ret.m128.val[0] = vld1q_s16((int16_t*)(re)); - ret.m128.val[1] = vld1q_s16((int16_t*)(im)); + ret.m128.val[0] = vld1q_s16(re); + ret.m128.val[1] = vld1q_s16(im); #endif /* HAVE_NEON */ #endif /* HAVE_SSE */ #endif /* HAVE_AVX2 */ return ret; } -static inline void srsran_simd_c16i_store(c16_t* ptr, simd_c16_t simdreg) +inline void srsran_simd_c16i_store(c16_t* ptr, simd_c16_t simdreg) { #ifdef HAVE_AVX2 __m256i re_sw = _mm256_shufflelo_epi16(_mm256_shufflehi_epi16(simdreg.re.m256, 0b10110001), 0b10110001); __m256i im_sw = _mm256_shufflelo_epi16(_mm256_shufflehi_epi16(simdreg.im.m256, 0b10110001), 0b10110001); - _mm256_store_si256((__m256i*)(ptr), _mm256_blend_epi16(simdreg.re.m256, im_sw, 0b10101010)); - _mm256_store_si256((__m256i*)(ptr + 8), _mm256_blend_epi16(re_sw, simdreg.im.m256, 0b10101010)); + _mm256_store_si256(reinterpret_cast<__m256i*>(ptr), _mm256_blend_epi16(simdreg.re.m256, im_sw, 0b10101010)); + _mm256_store_si256(reinterpret_cast<__m256i*>(ptr + 8), _mm256_blend_epi16(re_sw, simdreg.im.m256, 0b10101010)); #else #ifdef HAVE_SSE __m128i re_sw = _mm_shufflelo_epi16(_mm_shufflehi_epi16(simdreg.re.m128, 0b10110001), 0b10110001); __m128i im_sw = _mm_shufflelo_epi16(_mm_shufflehi_epi16(simdreg.im.m128, 0b10110001), 0b10110001); - _mm_store_si128((__m128i*)(ptr), _mm_blend_epi16(simdreg.re.m128, im_sw, 0b10101010)); - _mm_store_si128((__m128i*)(ptr + 8), _mm_blend_epi16(re_sw, simdreg.im.m128, 0b10101010)); -#else /*HAVE_NEON*/ + _mm_store_si128(reinterpret_cast<__m128i*>(ptr), _mm_blend_epi16(simdreg.re.m128, im_sw, 0b10101010)); + _mm_store_si128(reinterpret_cast<__m128i*>(ptr + 8), _mm_blend_epi16(re_sw, simdreg.im.m128, 0b10101010)); +#else /* HAVE_NEON */ #ifdef HAVE_NEON - vst2q_s16((int16_t*)(ptr), simdreg.m128); + vst2q_s16(reinterpret_cast(ptr), simdreg.m128); #endif /* HAVE_NEON */ #endif /* HAVE_SSE */ #endif /* HAVE_AVX2 */ } -static inline void srsran_simd_c16i_storeu(c16_t* ptr, simd_c16_t simdreg) +inline void srsran_simd_c16i_storeu(c16_t* ptr, simd_c16_t simdreg) { #ifdef HAVE_AVX2 __m256i re_sw = _mm256_shufflelo_epi16(_mm256_shufflehi_epi16(simdreg.re.m256, 0b10110001), 0b10110001); __m256i im_sw = _mm256_shufflelo_epi16(_mm256_shufflehi_epi16(simdreg.im.m256, 0b10110001), 0b10110001); - _mm256_storeu_si256((__m256i*)(ptr), _mm256_blend_epi16(simdreg.re.m256, im_sw, 0b10101010)); - _mm256_storeu_si256((__m256i*)(ptr + 8), _mm256_blend_epi16(re_sw, simdreg.im.m256, 0b10101010)); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(ptr), _mm256_blend_epi16(simdreg.re.m256, im_sw, 0b10101010)); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(ptr + 8), _mm256_blend_epi16(re_sw, simdreg.im.m256, 0b10101010)); #else #ifdef HAVE_SSE __m128i re_sw = _mm_shufflelo_epi16(_mm_shufflehi_epi16(simdreg.re.m128, 0b10110001), 0b10110001); __m128i im_sw = _mm_shufflelo_epi16(_mm_shufflehi_epi16(simdreg.im.m128, 0b10110001), 0b10110001); - _mm_storeu_si128((__m128i*)(ptr), _mm_blend_epi16(simdreg.re.m128, im_sw, 0b10101010)); - _mm_storeu_si128((__m128i*)(ptr + 8), _mm_blend_epi16(re_sw, simdreg.im.m128, 0b10101010)); -#else /*HAVE_NEON*/ + _mm_storeu_si128(reinterpret_cast<__m128i*>(ptr), _mm_blend_epi16(simdreg.re.m128, im_sw, 0b10101010)); + _mm_storeu_si128(reinterpret_cast<__m128i*>(ptr + 8), _mm_blend_epi16(re_sw, simdreg.im.m128, 0b10101010)); +#else /* HAVE_NEON */ #ifdef HAVE_NEON - vst2q_s16((int16_t*)(ptr), simdreg.m128); + vst2q_s16(reinterpret_cast(ptr), simdreg.m128); #endif /* HAVE_NEON */ #endif /* HAVE_SSE */ #endif /* HAVE_AVX2 */ } -static inline void srsran_simd_c16_store(int16_t* re, int16_t* im, simd_c16_t simdreg) +inline void srsran_simd_c16_store(int16_t* re, int16_t* im, simd_c16_t simdreg) { #ifdef HAVE_AVX2 - _mm256_store_si256((__m256i*)re, simdreg.re.m256); - _mm256_store_si256((__m256i*)im, simdreg.im.m256); + _mm256_store_si256(reinterpret_cast<__m256i*>(re), simdreg.re.m256); + _mm256_store_si256(reinterpret_cast<__m256i*>(im), simdreg.im.m256); #else #ifdef HAVE_SSE - _mm_store_si128((__m128i*)re, simdreg.re.m128); - _mm_store_si128((__m128i*)im, simdreg.im.m128); + _mm_store_si128(reinterpret_cast<__m128i*>(re), simdreg.re.m128); + _mm_store_si128(reinterpret_cast<__m128i*>(im), simdreg.im.m128); #else #ifdef HAVE_NEON - vst1q_s16((int16_t*)re, simdreg.m128.val[0]); - vst1q_s16((int16_t*)im, simdreg.m128.val[1]); + vst1q_s16(re, simdreg.m128.val[0]); + vst1q_s16(im, simdreg.m128.val[1]); #endif /* HAVE_NEON */ #endif /* HAVE_SSE */ #endif /* HAVE_AVX2 */ } -static inline void srsran_simd_c16_storeu(int16_t* re, int16_t* im, simd_c16_t simdreg) +inline void srsran_simd_c16_storeu(int16_t* re, int16_t* im, simd_c16_t simdreg) { #ifdef HAVE_AVX2 - _mm256_storeu_si256((__m256i*)re, simdreg.re.m256); - _mm256_storeu_si256((__m256i*)im, simdreg.im.m256); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(re), simdreg.re.m256); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(im), simdreg.im.m256); #else #ifdef HAVE_SSE - _mm_storeu_si128((__m128i*)re, simdreg.re.m128); - _mm_storeu_si128((__m128i*)im, simdreg.im.m128); + _mm_storeu_si128(reinterpret_cast<__m128i*>(re), simdreg.re.m128); + _mm_storeu_si128(reinterpret_cast<__m128i*>(im), simdreg.im.m128); #else #ifdef HAVE_NEON - vst1q_s16((int16_t*)re, simdreg.m128.val[0]); - vst1q_s16((int16_t*)im, simdreg.m128.val[1]); + vst1q_s16(re, simdreg.m128.val[0]); + vst1q_s16(im, simdreg.m128.val[1]); #endif /* HAVE_NEON */ #endif /* HAVE_SSE */ #endif /* HAVE_AVX2 */ } -static inline simd_c16_t srsran_simd_c16_prod(simd_c16_t a, simd_c16_t b) +inline simd_c16_t srsran_simd_c16_prod(simd_c16_t a, simd_c16_t b) { simd_c16_t ret; #ifdef HAVE_AVX2 @@ -1824,7 +1853,7 @@ static inline simd_c16_t srsran_simd_c16_prod(simd_c16_t a, simd_c16_t b) return ret; } -static inline simd_c16_t srsran_simd_c16_add(simd_c16_t a, simd_c16_t b) +inline simd_c16_t srsran_simd_c16_add(simd_c16_t a, simd_c16_t b) { simd_c16_t ret; #ifdef HAVE_AVX2 @@ -1844,7 +1873,7 @@ static inline simd_c16_t srsran_simd_c16_add(simd_c16_t a, simd_c16_t b) return ret; } -static inline simd_c16_t srsran_simd_c16_zero(void) +inline simd_c16_t srsran_simd_c16_zero() { simd_c16_t ret; #ifdef HAVE_AVX2 @@ -1868,7 +1897,7 @@ static inline simd_c16_t srsran_simd_c16_zero(void) #if SRSRAN_SIMD_F_SIZE && SRSRAN_SIMD_S_SIZE -static inline simd_s_t srsran_simd_convert_2f_s(simd_f_t a, simd_f_t b) +inline simd_s_t srsran_simd_convert_2f_s(simd_f_t a, simd_f_t b) { #ifdef HAVE_AVX512 __m512 aa = _mm512_permutex2var_ps( @@ -1910,33 +1939,37 @@ static inline simd_s_t srsran_simd_convert_2f_s(simd_f_t a, simd_f_t b) #endif /* SRSRAN_SIMD_F_SIZE && SRSRAN_SIMD_C16_SIZE */ #if SRSRAN_SIMD_B_SIZE -/* Data types */ + +/// +/// Data types. +/// + #ifdef HAVE_AVX512 -typedef __m512i simd_b_t; +using simd_b_t = __m512i; #else /* HAVE_AVX512 */ #ifdef HAVE_AVX2 -typedef __m256i simd_b_t; +using simd_b_t = __m256i; #else /* HAVE_AVX2 */ #ifdef HAVE_SSE -typedef __m128i simd_b_t; +using simd_b_t = __m128i; #else /* HAVE_NEON */ #ifdef HAVE_NEON -typedef int8x16_t simd_b_t; +using simd_b_t = int8x16_t; #endif /* HAVE_NEON */ #endif /* HAVE_SSE */ #endif /* HAVE_AVX2 */ #endif /* HAVE_AVX512 */ -static inline simd_b_t srsran_simd_b_load(const int8_t* ptr) +inline simd_b_t srsran_simd_b_load(const int8_t* ptr) { #ifdef HAVE_AVX512 return _mm512_load_si512(ptr); #else /* HAVE_AVX512 */ #ifdef HAVE_AVX2 - return _mm256_load_si256((__m256i*)ptr); + return _mm256_load_si256(reinterpret_cast(ptr)); #else /* HAVE_AVX2 */ #ifdef HAVE_SSE - return _mm_load_si128((__m128i*)ptr); + return _mm_load_si128(reinterpret_cast(ptr)); #else /* HAVE_SSE */ #ifdef HAVE_NEON return vld1q_s8(ptr); @@ -1946,16 +1979,16 @@ static inline simd_b_t srsran_simd_b_load(const int8_t* ptr) #endif /* HAVE_AVX512 */ } -static inline simd_b_t srsran_simd_b_loadu(const int8_t* ptr) +inline simd_b_t srsran_simd_b_loadu(const int8_t* ptr) { #ifdef HAVE_AVX512 return _mm512_loadu_si512(ptr); #else /* HAVE_AVX512 */ #ifdef HAVE_AVX2 - return _mm256_loadu_si256((__m256i*)ptr); + return _mm256_loadu_si256(reinterpret_cast(ptr)); #else /* HAVE_AVX2 */ #ifdef HAVE_SSE - return _mm_loadu_si128((__m128i*)ptr); + return _mm_loadu_si128(reinterpret_cast(ptr)); #else /* HAVE_SSE */ #ifdef HAVE_NEON return vld1q_s8(ptr); @@ -1965,16 +1998,16 @@ static inline simd_b_t srsran_simd_b_loadu(const int8_t* ptr) #endif /* HAVE_AVX512 */ } -static inline void srsran_simd_b_store(int8_t* ptr, simd_b_t simdreg) +inline void srsran_simd_b_store(int8_t* ptr, simd_b_t simdreg) { #ifdef HAVE_AVX512 _mm512_store_si512(ptr, simdreg); #else /* HAVE_AVX512 */ #ifdef HAVE_AVX2 - _mm256_store_si256((__m256i*)ptr, simdreg); + _mm256_store_si256(reinterpret_cast<__m256i*>(ptr), simdreg); #else /* HAVE_AVX2 */ #ifdef HAVE_SSE - _mm_store_si128((__m128i*)ptr, simdreg); + _mm_store_si128(reinterpret_cast<__m128i*>(ptr), simdreg); #else /* HAVE_SSE */ #ifdef HAVE_NEON vst1q_s8(ptr, simdreg); @@ -1984,16 +2017,16 @@ static inline void srsran_simd_b_store(int8_t* ptr, simd_b_t simdreg) #endif /* HAVE_AVX512 */ } -static inline void srsran_simd_b_storeu(int8_t* ptr, simd_b_t simdreg) +inline void srsran_simd_b_storeu(int8_t* ptr, simd_b_t simdreg) { #ifdef HAVE_AVX512 _mm512_storeu_si512(ptr, simdreg); #else /* HAVE_AVX512 */ #ifdef HAVE_AVX2 - _mm256_storeu_si256((__m256i*)ptr, simdreg); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(ptr), simdreg); #else /* HAVE_AVX2 */ #ifdef HAVE_SSE - _mm_storeu_si128((__m128i*)ptr, simdreg); + _mm_storeu_si128(reinterpret_cast<__m128i*>(ptr), simdreg); #else /* HAVE_SSE */ #ifdef HAVE_NEON vst1q_s8(ptr, simdreg); @@ -2003,7 +2036,7 @@ static inline void srsran_simd_b_storeu(int8_t* ptr, simd_b_t simdreg) #endif /* HAVE_AVX512 */ } -static inline simd_b_t srsran_simd_b_xor(simd_b_t a, simd_b_t b) +inline simd_b_t srsran_simd_b_xor(simd_b_t a, simd_b_t b) { #ifdef HAVE_AVX512 return _mm512_xor_epi32(a, b); @@ -2022,7 +2055,7 @@ static inline simd_b_t srsran_simd_b_xor(simd_b_t a, simd_b_t b) #endif /* HAVE_AVX512 */ } -static inline simd_b_t srsran_simd_b_add(simd_b_t a, simd_b_t b) +inline simd_b_t srsran_simd_b_add(simd_b_t a, simd_b_t b) { #ifdef HAVE_AVX512 return _mm512_adds_epi8(a, b); @@ -2041,7 +2074,7 @@ static inline simd_b_t srsran_simd_b_add(simd_b_t a, simd_b_t b) #endif /* HAVE_AVX512 */ } -static inline simd_b_t srsran_simd_b_sub(simd_b_t a, simd_b_t b) +inline simd_b_t srsran_simd_b_sub(simd_b_t a, simd_b_t b) { #ifdef HAVE_AVX512 return _mm512_subs_epi8(a, b); @@ -2060,7 +2093,7 @@ static inline simd_b_t srsran_simd_b_sub(simd_b_t a, simd_b_t b) #endif /* HAVE_AVX512 */ } -static inline simd_b_t srsran_simd_b_neg(simd_b_t a, simd_b_t b) +inline simd_b_t srsran_simd_b_neg(simd_b_t a, simd_b_t b) { #ifdef HAVE_AVX512 __m256i a0 = _mm512_extracti64x4_epi64(a, 0); @@ -2078,18 +2111,17 @@ static inline simd_b_t srsran_simd_b_neg(simd_b_t a, simd_b_t b) return _mm_sign_epi8(a, b); #else /* HAVE_SSE */ #ifdef HAVE_NEON - /* Taken and modified from sse2neon.h licensed under MIT - * Source: https://github.com/DLTcollab/sse2neon - */ + // Taken and modified from sse2neon.h licensed under MIT. + // Source: https://github.com/DLTcollab/sse2neon int8x16_t zero = vdupq_n_s8(0); - // signed shift right: faster than vclt + // Signed shift right: faster than vclt. // (b < 0) ? 0xff : 0 uint8x16_t ltMask = vreinterpretq_u8_s8(vshrq_n_s8(b, 7)); // (b == 0) ? 0xff : 0 int8x16_t zeroMask = vreinterpretq_s8_u8(vceqq_s8(b, zero)); // -a int8x16_t neg = vnegq_s8(a); - // bitwise select either a or neg based on ltMask + // Bitwise select either a or neg based on ltMask. int8x16_t masked = vbslq_s8(ltMask, neg, a); // res = masked & (~zeroMask) int8x16_t res = vbicq_s8(masked, zeroMask); @@ -2100,6 +2132,6 @@ static inline simd_b_t srsran_simd_b_neg(simd_b_t a, simd_b_t b) #endif /* HAVE_AVX512 */ } -#endif /*SRSRAN_SIMD_B_SIZE */ +#endif /* SRSRAN_SIMD_B_SIZE */ } // namespace srsran diff --git a/lib/srsvec/subtract.cpp b/lib/srsvec/subtract.cpp index ac14fb7ba9..86b7cd994d 100644 --- a/lib/srsvec/subtract.cpp +++ b/lib/srsvec/subtract.cpp @@ -40,7 +40,7 @@ static void subtract_fff_simd(float* z, const float* x, const float* y, std::siz } #endif - for (; i != len; i++) { + for (; i != len; ++i) { z[i] = x[i] - y[i]; } } @@ -71,7 +71,7 @@ static void subtract_sss_simd(int16_t* z, const int16_t* x, const int16_t* y, st } #endif /* SRSRAN_SIMD_S_SIZE */ - for (; i != len; i++) { + for (; i != len; ++i) { z[i] = x[i] - y[i]; } } @@ -102,7 +102,7 @@ static void subtract_bbb_simd(int8_t* z, const int8_t* x, const int8_t* y, std:: } #endif /* SRSRAN_SIMD_S_SIZE */ - for (; i != len; i++) { + for (; i != len; ++i) { z[i] = x[i] - y[i]; } } @@ -140,4 +140,4 @@ void srsran::srsvec::subtract(span z, span x, span Date: Fri, 23 Feb 2024 13:09:41 +0100 Subject: [PATCH 013/140] simd: review improvements --- include/srsran/srsvec/types.h | 3 +++ lib/srsvec/simd.h | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/srsran/srsvec/types.h b/include/srsran/srsvec/types.h index 3957ccccad..13d09c9cab 100644 --- a/include/srsran/srsvec/types.h +++ b/include/srsran/srsvec/types.h @@ -15,6 +15,8 @@ #include "srsran/support/srsran_assert.h" #include +/// \brief The srsvec library provides optimized SIMD commonly used operations. +/// /// The supported vector data types are: /// - srsran::span: For complex float vectors /// - srsran::span: For float vectors @@ -24,6 +26,7 @@ /// /// To make the span constant use srsran::span. +/// Asserts that both objects have the same size. #define srsran_srsvec_assert_size(X, Y) \ srsran_assert( \ X.size() == Y.size(), "The size " #X " (i.e., {}) and " #Y " (i.e., {}) must be equal.", X.size(), Y.size()) diff --git a/lib/srsvec/simd.h b/lib/srsvec/simd.h index 330957a418..02c974e79a 100644 --- a/lib/srsvec/simd.h +++ b/lib/srsvec/simd.h @@ -831,7 +831,7 @@ inline simd_f_t srsran_simd_cf_re(simd_cf_t in) #endif /* HAVE_NEON */ #ifndef HAVE_AVX512 #ifdef HAVE_AVX2 - // Permute for AVX registers (miss SSE registers). + // Permute for AVX registers (reorders data across 128-bit registers). const __m256i idx = _mm256_setr_epi32(0, 2, 4, 6, 1, 3, 5, 7); out = _mm256_permutevar8x32_ps(out, idx); #endif /* HAVE_AVX2 */ @@ -848,7 +848,7 @@ inline simd_f_t srsran_simd_cf_im(simd_cf_t in) #endif /* HAVE_NEON */ #ifndef HAVE_AVX512 #ifdef HAVE_AVX2 - // Permute for AVX registers (miss SSE registers). + // Permute for AVX registers (reorders data across 128-bit registers). const __m256i idx = _mm256_setr_epi32(0, 2, 4, 6, 1, 3, 5, 7); out = _mm256_permutevar8x32_ps(out, idx); #endif /* HAVE_AVX2 */ From 299641d9d6d9410214c61d055e904b799e120e46 Mon Sep 17 00:00:00 2001 From: faluco Date: Fri, 23 Feb 2024 13:37:20 +0100 Subject: [PATCH 014/140] simd: remove redundant unions for the simd_c16_t type --- lib/srsvec/simd.h | 149 ++++++++++++++++++++-------------------------- 1 file changed, 65 insertions(+), 84 deletions(-) diff --git a/lib/srsvec/simd.h b/lib/srsvec/simd.h index 02c974e79a..8bf6db4c48 100644 --- a/lib/srsvec/simd.h +++ b/lib/srsvec/simd.h @@ -1634,44 +1634,25 @@ inline simd_s_t srsran_simd_s_sub(simd_s_t a, simd_s_t b) #ifdef HAVE_AVX512 struct simd_c16_t { - union { - __m512i m512; - int16_t i16[32]; - } re; - union { - __m512i m512; - int16_t i16[32]; - } im; + __m512i re; + __m512i im; }; #else /* HAVE_AVX512 */ #ifdef HAVE_AVX2 struct simd_c16_t { - union { - __m256i m256; - int16_t i16[16]; - } re; - union { - __m256i m256; - int16_t i16[16]; - } im; + __m256i re; + __m256i im; }; #else #ifdef HAVE_SSE struct simd_c16_t { - union { - __m128i m128; - int16_t i16[8]; - } re; - union { - __m128i m128; - int16_t i16[8]; - } im; + __m128i re; + __m128i im; }; #else #ifdef HAVE_NEON -union simd_c16_t { +struct simd_c16_t { int16x8x2_t m128; - int16_t i16[16]; }; #endif /* HAVE_NEON */ #endif /* HAVE_SSE */ @@ -1688,24 +1669,24 @@ inline simd_c16_t srsran_simd_c16i_load(const c16_t* ptr) #ifdef HAVE_AVX512 __m512i in1 = _mm512_load_si512(reinterpret_cast(ptr)); __m512i in2 = _mm512_load_si512(reinterpret_cast(ptr + 8)); - ret.re.m512 = _mm512_mask_blend_epi16( + ret.re = _mm512_mask_blend_epi16( 0xaaaaaaaa, in1, _mm512_shufflelo_epi16(_mm512_shufflehi_epi16(in2, 0b10100000), 0b10100000)); - ret.im.m512 = _mm512_mask_blend_epi16( + ret.im = _mm512_mask_blend_epi16( 0xaaaaaaaa, _mm512_shufflelo_epi16(_mm512_shufflehi_epi16(in1, 0b11110101), 0b11110101), in2); #else /* HAVE_AVX2 */ #ifdef HAVE_AVX2 __m256i in1 = _mm256_load_si256(reinterpret_cast(ptr)); __m256i in2 = _mm256_load_si256(reinterpret_cast(ptr + 8)); - ret.re.m256 = + ret.re = _mm256_blend_epi16(in1, _mm256_shufflelo_epi16(_mm256_shufflehi_epi16(in2, 0b10100000), 0b10100000), 0b10101010); - ret.im.m256 = + ret.im = _mm256_blend_epi16(_mm256_shufflelo_epi16(_mm256_shufflehi_epi16(in1, 0b11110101), 0b11110101), in2, 0b10101010); #else /* HAVE_AVX2 */ #ifdef HAVE_SSE __m128i in1 = _mm_load_si128(reinterpret_cast(ptr)); __m128i in2 = _mm_load_si128(reinterpret_cast(ptr + 8)); - ret.re.m128 = _mm_blend_epi16(in1, _mm_shufflelo_epi16(_mm_shufflehi_epi16(in2, 0b10100000), 0b10100000), 0b10101010); - ret.im.m128 = _mm_blend_epi16(_mm_shufflelo_epi16(_mm_shufflehi_epi16(in1, 0b11110101), 0b11110101), in2, 0b10101010); + ret.re = _mm_blend_epi16(in1, _mm_shufflelo_epi16(_mm_shufflehi_epi16(in2, 0b10100000), 0b10100000), 0b10101010); + ret.im = _mm_blend_epi16(_mm_shufflelo_epi16(_mm_shufflehi_epi16(in1, 0b11110101), 0b11110101), in2, 0b10101010); #else /* HAVE_SSE*/ #ifdef HAVE_NEON ret.m128 = vld2q_s16(reinterpret_cast(ptr)); @@ -1720,12 +1701,12 @@ inline simd_c16_t srsran_simd_c16_load(const int16_t* re, const int16_t* im) { simd_c16_t ret; #ifdef HAVE_AVX2 - ret.re.m256 = _mm256_load_si256(reinterpret_cast(re)); - ret.im.m256 = _mm256_load_si256(reinterpret_cast(im)); + ret.re = _mm256_load_si256(reinterpret_cast(re)); + ret.im = _mm256_load_si256(reinterpret_cast(im)); #else #ifdef HAVE_SSE - ret.re.m128 = _mm_load_si128(reinterpret_cast(re)); - ret.im.m128 = _mm_load_si128(reinterpret_cast(im)); + ret.re = _mm_load_si128(reinterpret_cast(re)); + ret.im = _mm_load_si128(reinterpret_cast(im)); #else /* HAVE_SSE*/ #ifdef HAVE_NEON ret.m128.val[0] = vld1q_s16(re); @@ -1740,12 +1721,12 @@ inline simd_c16_t srsran_simd_c16_loadu(const int16_t* re, const int16_t* im) { simd_c16_t ret; #ifdef HAVE_AVX2 - ret.re.m256 = _mm256_loadu_si256(reinterpret_cast(re)); - ret.im.m256 = _mm256_loadu_si256(reinterpret_cast(im)); + ret.re = _mm256_loadu_si256(reinterpret_cast(re)); + ret.im = _mm256_loadu_si256(reinterpret_cast(im)); #else #ifdef HAVE_SSE - ret.re.m128 = _mm_loadu_si128(reinterpret_cast(re)); - ret.im.m128 = _mm_loadu_si128(reinterpret_cast(im)); + ret.re = _mm_loadu_si128(reinterpret_cast(re)); + ret.im = _mm_loadu_si128(reinterpret_cast(im)); #else /* HAVE_SSE*/ #ifdef HAVE_NEON ret.m128.val[0] = vld1q_s16(re); @@ -1759,16 +1740,16 @@ inline simd_c16_t srsran_simd_c16_loadu(const int16_t* re, const int16_t* im) inline void srsran_simd_c16i_store(c16_t* ptr, simd_c16_t simdreg) { #ifdef HAVE_AVX2 - __m256i re_sw = _mm256_shufflelo_epi16(_mm256_shufflehi_epi16(simdreg.re.m256, 0b10110001), 0b10110001); - __m256i im_sw = _mm256_shufflelo_epi16(_mm256_shufflehi_epi16(simdreg.im.m256, 0b10110001), 0b10110001); - _mm256_store_si256(reinterpret_cast<__m256i*>(ptr), _mm256_blend_epi16(simdreg.re.m256, im_sw, 0b10101010)); - _mm256_store_si256(reinterpret_cast<__m256i*>(ptr + 8), _mm256_blend_epi16(re_sw, simdreg.im.m256, 0b10101010)); + __m256i re_sw = _mm256_shufflelo_epi16(_mm256_shufflehi_epi16(simdreg.re, 0b10110001), 0b10110001); + __m256i im_sw = _mm256_shufflelo_epi16(_mm256_shufflehi_epi16(simdreg.im, 0b10110001), 0b10110001); + _mm256_store_si256(reinterpret_cast<__m256i*>(ptr), _mm256_blend_epi16(simdreg.re, im_sw, 0b10101010)); + _mm256_store_si256(reinterpret_cast<__m256i*>(ptr + 8), _mm256_blend_epi16(re_sw, simdreg.im, 0b10101010)); #else #ifdef HAVE_SSE - __m128i re_sw = _mm_shufflelo_epi16(_mm_shufflehi_epi16(simdreg.re.m128, 0b10110001), 0b10110001); - __m128i im_sw = _mm_shufflelo_epi16(_mm_shufflehi_epi16(simdreg.im.m128, 0b10110001), 0b10110001); - _mm_store_si128(reinterpret_cast<__m128i*>(ptr), _mm_blend_epi16(simdreg.re.m128, im_sw, 0b10101010)); - _mm_store_si128(reinterpret_cast<__m128i*>(ptr + 8), _mm_blend_epi16(re_sw, simdreg.im.m128, 0b10101010)); + __m128i re_sw = _mm_shufflelo_epi16(_mm_shufflehi_epi16(simdreg.re, 0b10110001), 0b10110001); + __m128i im_sw = _mm_shufflelo_epi16(_mm_shufflehi_epi16(simdreg.im, 0b10110001), 0b10110001); + _mm_store_si128(reinterpret_cast<__m128i*>(ptr), _mm_blend_epi16(simdreg.re, im_sw, 0b10101010)); + _mm_store_si128(reinterpret_cast<__m128i*>(ptr + 8), _mm_blend_epi16(re_sw, simdreg.im, 0b10101010)); #else /* HAVE_NEON */ #ifdef HAVE_NEON vst2q_s16(reinterpret_cast(ptr), simdreg.m128); @@ -1780,16 +1761,16 @@ inline void srsran_simd_c16i_store(c16_t* ptr, simd_c16_t simdreg) inline void srsran_simd_c16i_storeu(c16_t* ptr, simd_c16_t simdreg) { #ifdef HAVE_AVX2 - __m256i re_sw = _mm256_shufflelo_epi16(_mm256_shufflehi_epi16(simdreg.re.m256, 0b10110001), 0b10110001); - __m256i im_sw = _mm256_shufflelo_epi16(_mm256_shufflehi_epi16(simdreg.im.m256, 0b10110001), 0b10110001); - _mm256_storeu_si256(reinterpret_cast<__m256i*>(ptr), _mm256_blend_epi16(simdreg.re.m256, im_sw, 0b10101010)); - _mm256_storeu_si256(reinterpret_cast<__m256i*>(ptr + 8), _mm256_blend_epi16(re_sw, simdreg.im.m256, 0b10101010)); + __m256i re_sw = _mm256_shufflelo_epi16(_mm256_shufflehi_epi16(simdreg.re, 0b10110001), 0b10110001); + __m256i im_sw = _mm256_shufflelo_epi16(_mm256_shufflehi_epi16(simdreg.im, 0b10110001), 0b10110001); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(ptr), _mm256_blend_epi16(simdreg.re, im_sw, 0b10101010)); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(ptr + 8), _mm256_blend_epi16(re_sw, simdreg.im, 0b10101010)); #else #ifdef HAVE_SSE - __m128i re_sw = _mm_shufflelo_epi16(_mm_shufflehi_epi16(simdreg.re.m128, 0b10110001), 0b10110001); - __m128i im_sw = _mm_shufflelo_epi16(_mm_shufflehi_epi16(simdreg.im.m128, 0b10110001), 0b10110001); - _mm_storeu_si128(reinterpret_cast<__m128i*>(ptr), _mm_blend_epi16(simdreg.re.m128, im_sw, 0b10101010)); - _mm_storeu_si128(reinterpret_cast<__m128i*>(ptr + 8), _mm_blend_epi16(re_sw, simdreg.im.m128, 0b10101010)); + __m128i re_sw = _mm_shufflelo_epi16(_mm_shufflehi_epi16(simdreg.re, 0b10110001), 0b10110001); + __m128i im_sw = _mm_shufflelo_epi16(_mm_shufflehi_epi16(simdreg.im, 0b10110001), 0b10110001); + _mm_storeu_si128(reinterpret_cast<__m128i*>(ptr), _mm_blend_epi16(simdreg.re, im_sw, 0b10101010)); + _mm_storeu_si128(reinterpret_cast<__m128i*>(ptr + 8), _mm_blend_epi16(re_sw, simdreg.im, 0b10101010)); #else /* HAVE_NEON */ #ifdef HAVE_NEON vst2q_s16(reinterpret_cast(ptr), simdreg.m128); @@ -1801,12 +1782,12 @@ inline void srsran_simd_c16i_storeu(c16_t* ptr, simd_c16_t simdreg) inline void srsran_simd_c16_store(int16_t* re, int16_t* im, simd_c16_t simdreg) { #ifdef HAVE_AVX2 - _mm256_store_si256(reinterpret_cast<__m256i*>(re), simdreg.re.m256); - _mm256_store_si256(reinterpret_cast<__m256i*>(im), simdreg.im.m256); + _mm256_store_si256(reinterpret_cast<__m256i*>(re), simdreg.re); + _mm256_store_si256(reinterpret_cast<__m256i*>(im), simdreg.im); #else #ifdef HAVE_SSE - _mm_store_si128(reinterpret_cast<__m128i*>(re), simdreg.re.m128); - _mm_store_si128(reinterpret_cast<__m128i*>(im), simdreg.im.m128); + _mm_store_si128(reinterpret_cast<__m128i*>(re), simdreg.re); + _mm_store_si128(reinterpret_cast<__m128i*>(im), simdreg.im); #else #ifdef HAVE_NEON vst1q_s16(re, simdreg.m128.val[0]); @@ -1819,12 +1800,12 @@ inline void srsran_simd_c16_store(int16_t* re, int16_t* im, simd_c16_t simdreg) inline void srsran_simd_c16_storeu(int16_t* re, int16_t* im, simd_c16_t simdreg) { #ifdef HAVE_AVX2 - _mm256_storeu_si256(reinterpret_cast<__m256i*>(re), simdreg.re.m256); - _mm256_storeu_si256(reinterpret_cast<__m256i*>(im), simdreg.im.m256); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(re), simdreg.re); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(im), simdreg.im); #else #ifdef HAVE_SSE - _mm_storeu_si128(reinterpret_cast<__m128i*>(re), simdreg.re.m128); - _mm_storeu_si128(reinterpret_cast<__m128i*>(im), simdreg.im.m128); + _mm_storeu_si128(reinterpret_cast<__m128i*>(re), simdreg.re); + _mm_storeu_si128(reinterpret_cast<__m128i*>(im), simdreg.im); #else #ifdef HAVE_NEON vst1q_s16(re, simdreg.m128.val[0]); @@ -1838,16 +1819,16 @@ inline simd_c16_t srsran_simd_c16_prod(simd_c16_t a, simd_c16_t b) { simd_c16_t ret; #ifdef HAVE_AVX2 - ret.re.m256 = _mm256_sub_epi16(_mm256_mulhrs_epi16(a.re.m256, _mm256_slli_epi16(b.re.m256, 1)), - _mm256_mulhrs_epi16(a.im.m256, _mm256_slli_epi16(b.im.m256, 1))); - ret.im.m256 = _mm256_add_epi16(_mm256_mulhrs_epi16(a.re.m256, _mm256_slli_epi16(b.im.m256, 1)), - _mm256_mulhrs_epi16(a.im.m256, _mm256_slli_epi16(b.re.m256, 1))); + ret.re = _mm256_sub_epi16(_mm256_mulhrs_epi16(a.re, _mm256_slli_epi16(b.re, 1)), + _mm256_mulhrs_epi16(a.im, _mm256_slli_epi16(b.im, 1))); + ret.im = _mm256_add_epi16(_mm256_mulhrs_epi16(a.re, _mm256_slli_epi16(b.im, 1)), + _mm256_mulhrs_epi16(a.im, _mm256_slli_epi16(b.re, 1))); #else #ifdef HAVE_SSE - ret.re.m128 = _mm_sub_epi16(_mm_mulhrs_epi16(a.re.m128, _mm_slli_epi16(b.re.m128, 1)), - _mm_mulhrs_epi16(a.im.m128, _mm_slli_epi16(b.im.m128, 1))); - ret.im.m128 = _mm_add_epi16(_mm_mulhrs_epi16(a.re.m128, _mm_slli_epi16(b.im.m128, 1)), - _mm_mulhrs_epi16(a.im.m128, _mm_slli_epi16(b.re.m128, 1))); + ret.re = + _mm_sub_epi16(_mm_mulhrs_epi16(a.re, _mm_slli_epi16(b.re, 1)), _mm_mulhrs_epi16(a.im, _mm_slli_epi16(b.im, 1))); + ret.im = + _mm_add_epi16(_mm_mulhrs_epi16(a.re, _mm_slli_epi16(b.im, 1)), _mm_mulhrs_epi16(a.im, _mm_slli_epi16(b.re, 1))); #endif /* HAVE_SSE */ #endif /* HAVE_AVX2 */ return ret; @@ -1857,12 +1838,12 @@ inline simd_c16_t srsran_simd_c16_add(simd_c16_t a, simd_c16_t b) { simd_c16_t ret; #ifdef HAVE_AVX2 - ret.re.m256 = _mm256_add_epi16(a.re.m256, b.re.m256); - ret.im.m256 = _mm256_add_epi16(a.im.m256, b.im.m256); + ret.re = _mm256_add_epi16(a.re, b.re); + ret.im = _mm256_add_epi16(a.im, b.im); #else #ifdef HAVE_SSE - ret.re.m128 = _mm_add_epi16(a.re.m128, b.re.m128); - ret.im.m128 = _mm_add_epi16(a.im.m128, b.im.m128); + ret.re = _mm_add_epi16(a.re, b.re); + ret.im = _mm_add_epi16(a.im, b.im); #else #ifdef HAVE_NEON ret.m128.val[0] = vaddq_s16(a.m128.val[0], a.m128.val[0]); @@ -1877,12 +1858,12 @@ inline simd_c16_t srsran_simd_c16_zero() { simd_c16_t ret; #ifdef HAVE_AVX2 - ret.re.m256 = _mm256_setzero_si256(); - ret.im.m256 = _mm256_setzero_si256(); + ret.re = _mm256_setzero_si256(); + ret.im = _mm256_setzero_si256(); #else #ifdef HAVE_SSE - ret.re.m128 = _mm_setzero_si128(); - ret.im.m128 = _mm_setzero_si128(); + ret.re = _mm_setzero_si128(); + ret.im = _mm_setzero_si128(); #else #ifdef HAVE_NEON ret.m128.val[0] = vdupq_n_s16(0); @@ -1913,10 +1894,10 @@ inline simd_s_t srsran_simd_convert_2f_s(simd_f_t a, simd_f_t b) return _mm512_packs_epi32(ai, bi); #else /* HAVE_AVX512 */ #ifdef HAVE_AVX2 - __m256 aa = _mm256_round_ps(_mm256_permute2f128_ps(a, b, 0x20), _MM_FROUND_NINT); - __m256 bb = _mm256_round_ps(_mm256_permute2f128_ps(a, b, 0x31), _MM_FROUND_NINT); - __m256i ai = _mm256_cvtps_epi32(aa); - __m256i bi = _mm256_cvtps_epi32(bb); + __m256 aa = _mm256_round_ps(_mm256_permute2f128_ps(a, b, 0x20), _MM_FROUND_NINT); + __m256 bb = _mm256_round_ps(_mm256_permute2f128_ps(a, b, 0x31), _MM_FROUND_NINT); + __m256i ai = _mm256_cvtps_epi32(aa); + __m256i bi = _mm256_cvtps_epi32(bb); return _mm256_packs_epi32(ai, bi); #else #ifdef HAVE_SSE From d084eaa6bcb6eacc55b38757a8a5fbb458312dce Mon Sep 17 00:00:00 2001 From: Alejandro Leal Date: Sat, 24 Feb 2024 10:19:35 +0100 Subject: [PATCH 015/140] srsvec: fix compilation --- lib/srsvec/compare.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/srsvec/compare.cpp b/lib/srsvec/compare.cpp index 6474c0af49..0006fa7f45 100644 --- a/lib/srsvec/compare.cpp +++ b/lib/srsvec/compare.cpp @@ -79,8 +79,10 @@ const char* srsran::srsvec::detail::find(span input, const char* val std::pair srsran::srsvec::max_abs_element(span x) { - unsigned i = 0; - unsigned len = x.size(); + unsigned i = 0; + unsigned len = x.size(); + unsigned max_index = 0; + float max_abs2 = 0; #if SRSRAN_SIMD_CF_SIZE // Prepare range of indexes in SIMD register. @@ -124,8 +126,8 @@ std::pair srsran::srsvec::max_abs_element(span x) // Find maximum value within the vectors. float* it = std::max_element(simd_vector_max_values.begin(), simd_vector_max_values.end()); unsigned simd_max_index = static_cast(it - simd_vector_max_values.begin()); - unsigned max_index = simd_vector_max_indexes[simd_max_index]; - float max_abs2 = simd_vector_max_values[simd_max_index]; + max_index = simd_vector_max_indexes[simd_max_index]; + max_abs2 = simd_vector_max_values[simd_max_index]; #endif // SRSRAN_SIMD_CF_SIZE for (; i != len; ++i) { @@ -141,8 +143,10 @@ std::pair srsran::srsvec::max_abs_element(span x) std::pair srsran::srsvec::max_element(span x) { - unsigned i = 0; - unsigned len = x.size(); + unsigned i = 0; + unsigned len = x.size(); + unsigned max_index = 0; + float max_x = 0; #if SRSRAN_SIMD_CF_SIZE // Prepare range of indexes in SIMD register. @@ -178,8 +182,8 @@ std::pair srsran::srsvec::max_element(span x) // Find maximum value within the vectors. float* it = std::max_element(simd_vector_max_values.begin(), simd_vector_max_values.end()); unsigned simd_max_index = static_cast(it - simd_vector_max_values.begin()); - unsigned max_index = simd_vector_max_indexes[simd_max_index]; - float max_x = simd_vector_max_values[simd_max_index]; + max_index = simd_vector_max_indexes[simd_max_index]; + max_x = simd_vector_max_values[simd_max_index]; #endif // SRSRAN_SIMD_CF_SIZE for (; i != len; ++i) { From dbb59a6a3d58bc89fe9bfb5f9e59bd1ed25ed368 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Mon, 26 Feb 2024 10:35:38 +0100 Subject: [PATCH 016/140] cu_cp,f1ap: fix misc cause conversion --- lib/f1ap/cu_cp/f1ap_asn1_converters.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/f1ap/cu_cp/f1ap_asn1_converters.h b/lib/f1ap/cu_cp/f1ap_asn1_converters.h index 18ceddb3f6..db57fe9b12 100644 --- a/lib/f1ap/cu_cp/f1ap_asn1_converters.h +++ b/lib/f1ap/cu_cp/f1ap_asn1_converters.h @@ -57,6 +57,8 @@ inline asn1::f1ap::cause_c cause_to_f1ap_asn1(cause_t cause) { asn1::f1ap::cause_c f1ap_cause; + // TODO: Fix cause mapping + if (variant_holds_alternative(cause)) { f1ap_cause.set_radio_network() = static_cast(variant_get(cause)); @@ -67,7 +69,12 @@ inline asn1::f1ap::cause_c cause_to_f1ap_asn1(cause_t cause) f1ap_cause.set_protocol() = static_cast(variant_get(cause)); } else if (variant_holds_alternative(cause)) { - f1ap_cause.set_misc() = static_cast(variant_get(cause)); + // The mapping is not 1:1, so we need to handle the unspecified case separately + if (variant_get(cause) == cause_misc_t::unspecified) { + f1ap_cause.set_misc() = asn1::f1ap::cause_misc_opts::unspecified; + } else { + f1ap_cause.set_misc() = static_cast(variant_get(cause)); + } } else { report_fatal_error("Cannot convert cause to F1AP type"); } From 86250e4cd809d9f7e186377dda23ff4b8839174e Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Fri, 16 Feb 2024 09:36:55 +0100 Subject: [PATCH 017/140] du_high: intercept UCI indication and force HARQ-ACK=ACK and CSI only in case of testmode UE --- .../adapters/mac_test_mode_adapter.cpp | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/lib/du_high/adapters/mac_test_mode_adapter.cpp b/lib/du_high/adapters/mac_test_mode_adapter.cpp index cb97cd9a27..49e934ff20 100644 --- a/lib/du_high/adapters/mac_test_mode_adapter.cpp +++ b/lib/du_high/adapters/mac_test_mode_adapter.cpp @@ -359,39 +359,39 @@ void mac_test_mode_cell_adapter::handle_uci(const mac_uci_indication_message& ms if (not ue_info_mgr.is_test_ue(pdu.rnti)) { // non-test mode UE. Forward the original UCI indication PDU. msg_copy.ucis.push_back(pdu); - } - - // test mode UE. - // Intercept the UCI indication and force HARQ-ACK=ACK and CSI. - msg_copy.ucis.push_back(pdu); - mac_uci_pdu& test_uci = msg_copy.ucis.back(); - - bool entry_found = false; - if (variant_holds_alternative(test_uci.pdu)) { - for (const ul_sched_info& pusch : entry.puschs) { - if (pusch.pusch_cfg.rnti == pdu.rnti and pusch.uci.has_value()) { - fill_uci_pdu(variant_get(test_uci.pdu), pusch); - entry_found = true; - } - } } else { - // PUCCH case. - for (const pucch_info& pucch : entry.pucchs) { - if (pucch_info_and_uci_ind_match(pucch, test_uci)) { - // Intercept the UCI indication and force HARQ-ACK=ACK and UCI. - if (pucch.format == pucch_format::FORMAT_1) { - fill_uci_pdu(variant_get(test_uci.pdu), pucch); - } else { - fill_uci_pdu(variant_get(test_uci.pdu), pucch); + // test mode UE. + // Intercept the UCI indication and force HARQ-ACK=ACK and CSI. + msg_copy.ucis.push_back(pdu); + mac_uci_pdu& test_uci = msg_copy.ucis.back(); + + bool entry_found = false; + if (variant_holds_alternative(test_uci.pdu)) { + for (const ul_sched_info& pusch : entry.puschs) { + if (pusch.pusch_cfg.rnti == pdu.rnti and pusch.uci.has_value()) { + fill_uci_pdu(variant_get(test_uci.pdu), pusch); + entry_found = true; + } + } + } else { + // PUCCH case. + for (const pucch_info& pucch : entry.pucchs) { + if (pucch_info_and_uci_ind_match(pucch, test_uci)) { + // Intercept the UCI indication and force HARQ-ACK=ACK and UCI. + if (pucch.format == pucch_format::FORMAT_1) { + fill_uci_pdu(variant_get(test_uci.pdu), pucch); + } else { + fill_uci_pdu(variant_get(test_uci.pdu), pucch); + } + entry_found = true; } - entry_found = true; } } - } - if (not entry_found) { - msg_copy.ucis.pop_back(); - logger.warning("c-rnti={}: Mismatch between provided UCI and expected UCI for slot_rx={}", pdu.rnti, msg.sl_rx); + if (not entry_found) { + msg_copy.ucis.pop_back(); + logger.warning("c-rnti={}: Mismatch between provided UCI and expected UCI for slot_rx={}", pdu.rnti, msg.sl_rx); + } } } From 9e1f0ea6b9ccf3694f2a5b0e4554631956402931 Mon Sep 17 00:00:00 2001 From: asaezper Date: Mon, 26 Feb 2024 13:18:28 +0100 Subject: [PATCH 018/140] metrics: count num ues using a query --- .gitlab/ci/e2e/.env | 2 +- docker/README.md | 7 +++++++ docker/grafana/dashboards/home.json | 11 ++--------- docker/metrics_server/pyproject.toml | 2 +- .../metrics_server/src/metrics_server/__main__.py | 14 -------------- 5 files changed, 11 insertions(+), 25 deletions(-) diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index b0095dcd8c..30b3b5f79e 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -5,7 +5,7 @@ AMARISOFT_VERSION=2023-03-17 SRSUE_VERSION=23.11 OPEN5GS_VERSION=2.6.1 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin -METRICS_SERVER_VERSION=1.5.2 +METRICS_SERVER_VERSION=1.6.0 DPDK_VERSION=23.11 ZMQ_HOSTLABEL_0=kubernetes.io/hostname=k8s-worker-vm2 ZMQ_HOSTLABEL_1=kubernetes.io/hostname=k8s-worker-vm2 diff --git a/docker/README.md b/docker/README.md index f8de8bec06..c7ded8a34b 100644 --- a/docker/README.md +++ b/docker/README.md @@ -12,6 +12,13 @@ To launch the full multi-container solution, please run: docker compose -f docker/docker-compose.yml up ``` +or + +```bash +cd docker/ +docker compose up +``` + - To force a new build of the containers (including a new build of srsRAN gnb), please add a `--build` flag at the end of the previous command. - To run it in background, please add a `-d` flag at the end of the previous command. - For more options, check `docker compose up --help` diff --git a/docker/grafana/dashboards/home.json b/docker/grafana/dashboards/home.json index 95647029e7..dbb47a7f58 100644 --- a/docker/grafana/dashboards/home.json +++ b/docker/grafana/dashboards/home.json @@ -142,7 +142,7 @@ "type": "influxdb", "uid": "JOSE3g9KVz" }, - "query": "from(bucket: \"srsran\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"ue_count\")\n |> filter(fn: (r) => r[\"testbed\"] == \"default\")\n |> filter(fn: (r) => r[\"_field\"] == \"value\")\n |> last()", + "query": "from(bucket: \"srsran\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"ue_info\")\n |> filter(fn: (r) => r[\"testbed\"] == \"default\")\n |> filter(fn: (r) => r[\"_field\"] == \"dl_brate\")\n |> group(columns: [\"_time\"])\n |> count(column: \"rnti\")\n |> map(fn: (r) => ({ r with _value: r[\"rnti\"] }))\n |> drop(columns: [\"rnti\"])\n |> group()", "refId": "A" } ], @@ -162,7 +162,6 @@ "mode": "palette-classic" }, "custom": { - "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", @@ -237,7 +236,7 @@ "type": "influxdb", "uid": "JOSE3g9KVz" }, - "query": "from(bucket: \"srsran\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"ue_count\")\n |> filter(fn: (r) => r[\"testbed\"] == \"default\")\n |> filter(fn: (r) => r[\"_field\"] == \"value\")", + "query": "from(bucket: \"srsran\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"ue_info\")\n |> filter(fn: (r) => r[\"testbed\"] == \"default\")\n |> filter(fn: (r) => r[\"_field\"] == \"dl_brate\")\n |> group(columns: [\"_time\"])\n |> count(column: \"rnti\")\n |> map(fn: (r) => ({ r with _value: r[\"rnti\"] }))\n |> drop(columns: [\"rnti\"])\n |> group()", "refId": "Downlink" } ], @@ -409,7 +408,6 @@ "mode": "palette-classic" }, "custom": { - "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", @@ -510,7 +508,6 @@ "mode": "palette-classic" }, "custom": { - "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", @@ -616,7 +613,6 @@ "mode": "palette-classic" }, "custom": { - "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", @@ -717,7 +713,6 @@ "mode": "palette-classic" }, "custom": { - "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", @@ -823,7 +818,6 @@ "mode": "palette-classic" }, "custom": { - "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", @@ -929,7 +923,6 @@ "mode": "palette-classic" }, "custom": { - "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", diff --git a/docker/metrics_server/pyproject.toml b/docker/metrics_server/pyproject.toml index b9145f4776..9cea0a9b75 100644 --- a/docker/metrics_server/pyproject.toml +++ b/docker/metrics_server/pyproject.toml @@ -31,7 +31,7 @@ description = "srsRAN Metrics Server" name = "srs_metrics_server" readme = "README.md" requires-python = ">=3.7" -version = "1.5.2" +version = "1.6.0" [project.scripts] metrics-server = "metrics_server.__main__:main" diff --git a/docker/metrics_server/src/metrics_server/__main__.py b/docker/metrics_server/src/metrics_server/__main__.py index 6edfe9542d..996d285205 100644 --- a/docker/metrics_server/src/metrics_server/__main__.py +++ b/docker/metrics_server/src/metrics_server/__main__.py @@ -149,20 +149,6 @@ def _publish_data( # Currently we only support ue_list metric if "ue_list" in metric: timestamp = datetime.utcfromtimestamp(metric["timestamp"]).isoformat() - # Number of UEs measurement - _influx_push( - write_api, - bucket=bucket, - record={ - "measurement": "ue_count", - "tags": { - "testbed": testbed, - }, - "fields": {"value": len(metric["ue_list"])}, - "time": timestamp, - }, - record_time_key="time", - ) # UE Info measurement for ue_info in metric["ue_list"]: ue_container = ue_info["ue_container"] From 331df1c4bef45e6da5f6ea5a63d932091a690f6d Mon Sep 17 00:00:00 2001 From: asaezper Date: Mon, 26 Feb 2024 15:13:07 +0100 Subject: [PATCH 019/140] ci: codechecker analysis fix --- .gitlab-ci.yml | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d5001c184f..46bab8a798 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -148,6 +148,7 @@ full-code-format: KUBERNETES_CPU_LIMIT: 6 KUBERNETES_MEMORY_REQUEST: 12Gi KUBERNETES_MEMORY_LIMIT: 12Gi + CHECK_PER_FILE_TIMEOUT: 600 before_script: - | echo " @@ -168,7 +169,21 @@ full-code-format: cd build || exit cmake -DASSERT_LEVEL=PARANOID -DAUTO_DETECT_ISA=False -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DBUILD_TESTS=False .. make srsran_build_info # needed to generate hashes.h + - | + monitor_child_process() { + while true; do + ps -eo comm,pid,etimes | grep ${ANALYZER} | while read comm pid etimes; do + if [ $etimes -gt $CHECK_PER_FILE_TIMEOUT ]; then + echo "Killing child analysis process" + kill $pid + fi + done + sleep 30 + done + } + export -f monitor_child_process script: + - nohup bash -c monitor_child_process & - static-analyzer.sh -i /tmp/codechecker_skip --jobs ${KUBERNETES_CPU_REQUEST} --analyzers ${ANALYZER} ${ANALYZER_ARGS} $CI_PROJECT_DIR after_script: - mv codechecker_html codechecker-${ANALYZER}-html @@ -179,7 +194,6 @@ full-code-format: - codechecker-${ANALYZER}-html${ARTIFACT_EXTRA_PATH} when: always expire_in: 10 minutes - timeout: 8 hours # clangsa is slow clang-tidy: extends: .codechecker @@ -199,6 +213,7 @@ cppcheck: rules: - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ interruptible: false + retry: 2 variables: ANALYZER: cppcheck ANALYZER_ARGS: --cppcheck-max-template-recursion 5 @@ -219,6 +234,7 @@ clangsa: variables: ANALYZER: clangsa ANALYZER_ARGS: --ctu + timeout: 8 hours .coverity_base: image: $CR_REGISTRY_URI/coverity_image/2022.6.0:1.0.0 @@ -440,7 +456,7 @@ disable current schedule: - if: $CI_DESCRIPTION =~ /Alternative OSs/ when: always - if: $CI_DESCRIPTION =~ /Weekly/ - when: always + when: always interruptible: false variables: ENABLE: "false" From b14bef565d3e254f5080565ac07b724cab9c2f18 Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Thu, 1 Feb 2024 15:44:56 +0100 Subject: [PATCH 020/140] tests,e2: add two e2 test base classes --- tests/unittests/e2/common/e2_test_helpers.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/unittests/e2/common/e2_test_helpers.h b/tests/unittests/e2/common/e2_test_helpers.h index 6c97d2646e..071e058fde 100644 --- a/tests/unittests/e2/common/e2_test_helpers.h +++ b/tests/unittests/e2/common/e2_test_helpers.h @@ -781,7 +781,7 @@ class dummy_du_configurator : public du_configurator }; /// Fixture class for E2AP -class e2_test_base : public ::testing::Test +class e2_base { protected: void tick() @@ -814,6 +814,12 @@ class e2_test_base : public ::testing::Test srslog::basic_logger& test_logger = srslog::fetch_basic_logger("TEST"); }; +class e2_test_base : public e2_base, public ::testing::Test +{}; + +class e2_test_base_with_pcap : public e2_base, public testing::TestWithParam +{}; + class e2_test : public e2_test_base { void SetUp() override From 8a1a589499d9b2b7d87ab6195d6f33d3bdd9e88f Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Thu, 1 Feb 2024 15:46:56 +0100 Subject: [PATCH 021/140] tests,e2: allow to enable pcap output with cmd parameter --- tests/unittests/e2/e2sm_kpm_test.cpp | 209 ++++++++++++++++----------- 1 file changed, 126 insertions(+), 83 deletions(-) diff --git a/tests/unittests/e2/e2sm_kpm_test.cpp b/tests/unittests/e2/e2sm_kpm_test.cpp index 16ed726f96..87f4b28049 100644 --- a/tests/unittests/e2/e2sm_kpm_test.cpp +++ b/tests/unittests/e2/e2sm_kpm_test.cpp @@ -15,28 +15,24 @@ #include "srsran/support/async/async_test_utils.h" #include "srsran/support/executors/task_worker.h" #include "srsran/support/test_utils.h" +#include #include using namespace srsran; -#define PCAP_OUTPUT 0 +// Helper global variables to pass pcap_writer to all tests. +bool g_enable_pcap = false; +dlt_pcap* g_pcap = nullptr; -class e2sm_kpm_indication : public e2_test_base +class e2sm_kpm_indication : public e2_test_base_with_pcap { -public: -#if PCAP_OUTPUT - void save_msg_pcap(const byte_buffer& last_pdu) - { - if (not g_pcap->is_write_enabled()) { - return; - } - g_pcap->push_pdu(last_pdu.copy()); - usleep(200); - } -#endif -private: +protected: + dlt_pcap* external_pcap_writer; + void SetUp() override { + external_pcap_writer = GetParam(); + srslog::fetch_basic_logger("TEST").set_level(srslog::basic_levels::debug); srslog::init(); @@ -49,22 +45,19 @@ class e2sm_kpm_indication : public e2_test_base e2sm_kpm_iface = std::make_unique(test_logger, *e2sm_kpm_packer, *du_meas_provider); gw = std::make_unique(); pcap = std::make_unique(); - packer = std::make_unique(*gw, *e2, *pcap); -#if PCAP_OUTPUT - g_pcap = std::make_unique(155, "E2AP", "/tmp/e2sm_kpm_test.pcap", pcap_exec); -#endif + if (external_pcap_writer) { + packer = std::make_unique(*gw, *e2, *external_pcap_writer); + } else { + packer = std::make_unique(*gw, *e2, *pcap); + } } + void TearDown() override { // Flush logger after each test. srslog::flush(); pcap->close(); } -#if PCAP_OUTPUT - srsran::task_worker worker{"pcap_worker", 1024}; - task_worker_executor pcap_exec{worker}; - std::unique_ptr g_pcap; -#endif }; void get_presence_starting_with_cond_satisfied(const std::vector& presence, @@ -122,7 +115,37 @@ std::vector get_reported_ues(const std::vector>& return reported_ues; } -TEST_F(e2sm_kpm_indication, e2sm_kpm_generates_ric_indication_style1) +// E2 Setup Request is needed for Wireshark to correctly decode the subsequent Subscription Requests +TEST_F(e2_entity_test, e2sm_kpm_generates_ran_func_desc) +{ + if (!g_enable_pcap) { + return; + } + + dummy_e2_pdu_notifier* dummy_msg_notifier = e2_client->get_e2_msg_notifier(); + // We need this test to generate E2 Setup Request, so Wireshark can decode the following RIC indication messages. + test_logger.info("Launch e2 setup request procedure with task worker..."); + e2->start(); + + if (g_pcap) { + if (g_pcap->is_write_enabled()) { + g_pcap->push_pdu(gw->last_pdu.copy()); + } + } + + // Need to send setup response, so the transaction can be completed. + unsigned transaction_id = get_transaction_id(dummy_msg_notifier->last_e2_msg.pdu).value(); + e2_message e2_setup_response = generate_e2_setup_response(transaction_id); + e2_setup_response.pdu.successful_outcome() + .value.e2setup_resp() + ->ra_nfunctions_accepted.value[0] + ->ra_nfunction_id_item() + .ran_function_id = e2sm_kpm_asn1_packer::ran_func_id; + test_logger.info("Injecting E2SetupResponse"); + e2->handle_message(e2_setup_response); +} + +TEST_P(e2sm_kpm_indication, e2sm_kpm_generates_ric_indication_style1) { // Measurement values in 5 time slot. std::vector meas_values = {0.15625, 0.15625, 0.15625, 0.15625, 0.15625}; @@ -153,12 +176,11 @@ TEST_F(e2sm_kpm_indication, e2sm_kpm_generates_ric_indication_style1) "DRB.RlcSduDelayDl"); // Change to a valid metric. ric_action = generate_e2sm_kpm_ric_action(action_def); -#if PCAP_OUTPUT - // Save E2 Subscription Request. - e2_message e2_subscript_req = generate_e2sm_kpm_subscription_request(ric_action); - packer->handle_message(e2_subscript_req); - save_msg_pcap(gw->last_pdu); -#endif + if (g_enable_pcap) { + // Save E2 Subscription Request. + e2_message e2_subscript_req = generate_e2sm_kpm_subscription_request(ric_action); + packer->handle_message(e2_subscript_req); + } ASSERT_TRUE(e2sm_kpm_iface->action_supported(ric_action)); auto report_service = e2sm_kpm_iface->get_e2sm_report_service(ric_action.ric_action_definition); @@ -194,14 +216,13 @@ TEST_F(e2sm_kpm_indication, e2sm_kpm_generates_ric_indication_style1) ric_ind_msg.ind_msg_formats.ind_msg_format1().meas_data[i].meas_record[0].real().value); } -#if PCAP_OUTPUT - e2_message e2_msg = generate_e2_ind_msg(ind_hdr_bytes, ind_msg_bytes); - packer->handle_message(e2_msg); - save_msg_pcap(gw->last_pdu); -#endif + if (g_enable_pcap) { + e2_message e2_msg = generate_e2_ind_msg(ind_hdr_bytes, ind_msg_bytes); + packer->handle_message(e2_msg); + } } -TEST_F(e2sm_kpm_indication, e2sm_kpm_generates_ric_indication_style2) +TEST_P(e2sm_kpm_indication, e2sm_kpm_generates_ric_indication_style2) { std::vector ue_ids = {31}; du_meas_provider->set_ue_ids(ue_ids); @@ -244,12 +265,11 @@ TEST_F(e2sm_kpm_indication, e2sm_kpm_generates_ric_indication_style2) action_def_f2.subscript_info.meas_info_list[0].meas_type.set_meas_name().from_string("DRB.UEThpDl"); ric_action = generate_e2sm_kpm_ric_action(action_def); -#if PCAP_OUTPUT - // Save E2 Subscription Request. - e2_message e2_subscript_req = generate_e2sm_kpm_subscription_request(ric_action); - packer->handle_message(e2_subscript_req); - save_msg_pcap(gw->last_pdu); -#endif + if (g_enable_pcap) { + // Save E2 Subscription Request. + e2_message e2_subscript_req = generate_e2sm_kpm_subscription_request(ric_action); + packer->handle_message(e2_subscript_req); + } ASSERT_TRUE(e2sm_kpm_iface->action_supported(ric_action)); auto report_service = e2sm_kpm_iface->get_e2sm_report_service(ric_action.ric_action_definition); @@ -296,14 +316,13 @@ TEST_F(e2sm_kpm_indication, e2sm_kpm_generates_ric_indication_style2) } } -#if PCAP_OUTPUT - e2_message e2_msg = generate_e2_ind_msg(ind_hdr_bytes, ind_msg_bytes); - packer->handle_message(e2_msg); - save_msg_pcap(gw->last_pdu); -#endif + if (g_enable_pcap) { + e2_message e2_msg = generate_e2_ind_msg(ind_hdr_bytes, ind_msg_bytes); + packer->handle_message(e2_msg); + } } -TEST_F(e2sm_kpm_indication, e2sm_kpm_generates_ric_indication_style3) +TEST_P(e2sm_kpm_indication, e2sm_kpm_generates_ric_indication_style3) { std::vector ue_ids = {32, 129, 2, 15, 8}; du_meas_provider->set_ue_ids(ue_ids); @@ -394,12 +413,11 @@ TEST_F(e2sm_kpm_indication, e2sm_kpm_generates_ric_indication_style3) action_def_f3.meas_cond_list[0].meas_type.set_meas_name().from_string("DRB.UEThpDl"); // Change to a valid metric. ric_action = generate_e2sm_kpm_ric_action(action_def); -#if PCAP_OUTPUT - // Save E2 Subscription Request. - e2_message e2_subscript_req = generate_e2sm_kpm_subscription_request(ric_action); - packer->handle_message(e2_subscript_req); - save_msg_pcap(gw->last_pdu); -#endif + if (g_enable_pcap) { + // Save E2 Subscription Request. + e2_message e2_subscript_req = generate_e2sm_kpm_subscription_request(ric_action); + packer->handle_message(e2_subscript_req); + } ASSERT_TRUE(e2sm_kpm_iface->action_supported(ric_action)); auto report_service = e2sm_kpm_iface->get_e2sm_report_service(ric_action.ric_action_definition); @@ -455,14 +473,13 @@ TEST_F(e2sm_kpm_indication, e2sm_kpm_generates_ric_indication_style3) } } -#if PCAP_OUTPUT - e2_message e2_msg = generate_e2_ind_msg(ind_hdr_bytes, ind_msg_bytes); - packer->handle_message(e2_msg); - save_msg_pcap(gw->last_pdu); -#endif + if (g_enable_pcap) { + e2_message e2_msg = generate_e2_ind_msg(ind_hdr_bytes, ind_msg_bytes); + packer->handle_message(e2_msg); + } } -TEST_F(e2sm_kpm_indication, e2sm_kpm_generates_ric_indication_style4) +TEST_P(e2sm_kpm_indication, e2sm_kpm_generates_ric_indication_style4) { std::vector ue_ids = {23, 3, 14, 2, 9}; du_meas_provider->set_ue_ids(ue_ids); @@ -541,12 +558,11 @@ TEST_F(e2sm_kpm_indication, e2sm_kpm_generates_ric_indication_style4) subscription_info.meas_info_list[0].meas_type.set_meas_name().from_string("DRB.UEThpDl"); // change to a valid metric ric_action = generate_e2sm_kpm_ric_action(action_def); -#if PCAP_OUTPUT - // Save E2 Subscription Request. - e2_message e2_subscript_req = generate_e2sm_kpm_subscription_request(ric_action); - packer->handle_message(e2_subscript_req); - save_msg_pcap(gw->last_pdu); -#endif + if (g_enable_pcap) { + // Save E2 Subscription Request. + e2_message e2_subscript_req = generate_e2sm_kpm_subscription_request(ric_action); + packer->handle_message(e2_subscript_req); + } ASSERT_TRUE(e2sm_kpm_iface->action_supported(ric_action)); auto report_service = e2sm_kpm_iface->get_e2sm_report_service(ric_action.ric_action_definition); @@ -601,14 +617,13 @@ TEST_F(e2sm_kpm_indication, e2sm_kpm_generates_ric_indication_style4) } } -#if PCAP_OUTPUT - e2_message e2_msg = generate_e2_ind_msg(ind_hdr_bytes, ind_msg_bytes); - packer->handle_message(e2_msg); - save_msg_pcap(gw->last_pdu); -#endif + if (g_enable_pcap) { + e2_message e2_msg = generate_e2_ind_msg(ind_hdr_bytes, ind_msg_bytes); + packer->handle_message(e2_msg); + } } -TEST_F(e2sm_kpm_indication, e2sm_kpm_generates_ric_indication_style5) +TEST_P(e2sm_kpm_indication, e2sm_kpm_generates_ric_indication_style5) { std::vector ue_ids = {2, 81, 22, 5, 18}; du_meas_provider->set_ue_ids(ue_ids); @@ -668,12 +683,11 @@ TEST_F(e2sm_kpm_indication, e2sm_kpm_generates_ric_indication_style5) subscript_info.meas_info_list[0].meas_type.set_meas_name().from_string("DRB.UEThpDl"); // Change to a valid metric. ric_action = generate_e2sm_kpm_ric_action(action_def); -#if PCAP_OUTPUT - // Save E2 Subscription Request. - e2_message e2_subscript_req = generate_e2sm_kpm_subscription_request(ric_action); - packer->handle_message(e2_subscript_req); - save_msg_pcap(gw->last_pdu); -#endif + if (g_enable_pcap) { + // Save E2 Subscription Request. + e2_message e2_subscript_req = generate_e2sm_kpm_subscription_request(ric_action); + packer->handle_message(e2_subscript_req); + } ASSERT_TRUE(e2sm_kpm_iface->action_supported(ric_action)); auto report_service = e2sm_kpm_iface->get_e2sm_report_service(ric_action.ric_action_definition); @@ -728,9 +742,38 @@ TEST_F(e2sm_kpm_indication, e2sm_kpm_generates_ric_indication_style5) } } -#if PCAP_OUTPUT - e2_message e2_msg = generate_e2_ind_msg(ind_hdr_bytes, ind_msg_bytes); - packer->handle_message(e2_msg); - save_msg_pcap(gw->last_pdu); -#endif + if (g_enable_pcap) { + e2_message e2_msg = generate_e2_ind_msg(ind_hdr_bytes, ind_msg_bytes); + packer->handle_message(e2_msg); + } +} + +INSTANTIATE_TEST_SUITE_P(e2sm_kpm_tests, e2sm_kpm_indication, testing::Values(g_pcap)); + +int main(int argc, char** argv) +{ + // Check for '--enable_pcap' cmd line argument, do not use getopt as it interferes with gtest. + for (int i = 1; i < argc; ++i) { + std::string arg = argv[i]; + if (arg == "--enable_pcap") { + g_enable_pcap = true; + } + } + + srslog::init(); + + std::unique_ptr pcap_exec; + std::unique_ptr pcap_worker; + std::unique_ptr common_pcap_writer; + + if (g_enable_pcap) { + pcap_worker = std::make_unique("pcap_worker", 128); + pcap_exec = std::make_unique(*pcap_worker); + common_pcap_writer = create_e2ap_pcap("/tmp/e2sm_kpm_test.pcap", *pcap_exec); + g_pcap = common_pcap_writer.get(); + } + + ::testing::InitGoogleTest(&argc, argv); + int ret = RUN_ALL_TESTS(); + return ret; } From 4712b7e00168fd120b24abbcb7a30b02e3795b05 Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Fri, 9 Feb 2024 17:26:35 +0100 Subject: [PATCH 022/140] e2sm_kpm,test: report integer and real values in the same MeasDataItem --- tests/unittests/e2/common/e2_test_helpers.h | 15 ++-- tests/unittests/e2/e2sm_kpm_test.cpp | 76 +++++++++++++++------ 2 files changed, 64 insertions(+), 27 deletions(-) diff --git a/tests/unittests/e2/common/e2_test_helpers.h b/tests/unittests/e2/common/e2_test_helpers.h index 071e058fde..dfdbef1706 100644 --- a/tests/unittests/e2/common/e2_test_helpers.h +++ b/tests/unittests/e2/common/e2_test_helpers.h @@ -385,7 +385,7 @@ class dummy_e2sm_kpm_du_meas_provider : public e2sm_kpm_meas_provider } } else { if (meas_values_int.size()) { - meas_record_item.integer() = meas_values_int[0]; + meas_record_item.set_integer() = meas_values_int[0]; } else { meas_record_item.set_integer() = 1; } @@ -473,12 +473,13 @@ class dummy_e2sm_kpm_du_meas_provider : public e2sm_kpm_meas_provider return false; }; - std::vector supported_metrics = {"CQI", "RSRP", "RSRQ", "DRB.UEThpDl", "DRB.RlcSduDelayDl"}; - std::vector presence = {1}; - std::vector cond_satisfied = {1}; - std::vector meas_values_float = {0.15625}; - std::vector meas_values_int = {1}; - std::vector ue_ids = {0}; + std::vector supported_metrics = + {"CQI", "RSRP", "RSRQ", "DRB.UEThpDl", "DRB.UEThpUl", "DRB.RlcSduDelayDl"}; + std::vector presence = {1}; + std::vector cond_satisfied = {1}; + std::vector meas_values_float = {0.15625}; + std::vector meas_values_int = {1}; + std::vector ue_ids = {0}; }; class dummy_e2_subscription_mngr : public e2_subscription_manager diff --git a/tests/unittests/e2/e2sm_kpm_test.cpp b/tests/unittests/e2/e2sm_kpm_test.cpp index 87f4b28049..f7969f19b9 100644 --- a/tests/unittests/e2/e2sm_kpm_test.cpp +++ b/tests/unittests/e2/e2sm_kpm_test.cpp @@ -24,6 +24,45 @@ using namespace srsran; bool g_enable_pcap = false; dlt_pcap* g_pcap = nullptr; +class e2_entity_test_with_pcap : public e2_test_base_with_pcap +{ +protected: + dlt_pcap* external_pcap_writer; + + void SetUp() override + { + external_pcap_writer = GetParam(); + + srslog::fetch_basic_logger("TEST").set_level(srslog::basic_levels::debug); + srslog::init(); + + cfg = srsran::config_helpers::make_default_e2ap_config(); + cfg.e2sm_kpm_enabled = true; + + gw = std::make_unique(); + pcap = std::make_unique(); + if (external_pcap_writer) { + packer = std::make_unique(*gw, *e2, *external_pcap_writer); + } else { + packer = std::make_unique(*gw, *e2, *pcap); + } + e2_client = std::make_unique(*packer); + du_metrics = std::make_unique(); + f1ap_ue_id_mapper = std::make_unique(); + factory = timer_factory{timers, task_worker}; + rc_param_configurator = std::make_unique(); + e2 = create_e2_entity( + cfg, e2_client.get(), *du_metrics, *f1ap_ue_id_mapper, *rc_param_configurator, factory, task_worker); + } + + void TearDown() override + { + // flush logger after each test + srslog::flush(); + pcap->close(); + } +}; + class e2sm_kpm_indication : public e2_test_base_with_pcap { protected: @@ -116,23 +155,13 @@ std::vector get_reported_ues(const std::vector>& } // E2 Setup Request is needed for Wireshark to correctly decode the subsequent Subscription Requests -TEST_F(e2_entity_test, e2sm_kpm_generates_ran_func_desc) +TEST_P(e2_entity_test_with_pcap, e2sm_kpm_generates_ran_func_desc) { - if (!g_enable_pcap) { - return; - } - dummy_e2_pdu_notifier* dummy_msg_notifier = e2_client->get_e2_msg_notifier(); // We need this test to generate E2 Setup Request, so Wireshark can decode the following RIC indication messages. test_logger.info("Launch e2 setup request procedure with task worker..."); e2->start(); - if (g_pcap) { - if (g_pcap->is_write_enabled()) { - g_pcap->push_pdu(gw->last_pdu.copy()); - } - } - // Need to send setup response, so the transaction can be completed. unsigned transaction_id = get_transaction_id(dummy_msg_notifier->last_e2_msg.pdu).value(); e2_message e2_setup_response = generate_e2_setup_response(transaction_id); @@ -148,10 +177,11 @@ TEST_F(e2_entity_test, e2sm_kpm_generates_ran_func_desc) TEST_P(e2sm_kpm_indication, e2sm_kpm_generates_ric_indication_style1) { // Measurement values in 5 time slot. - std::vector meas_values = {0.15625, 0.15625, 0.15625, 0.15625, 0.15625}; - uint32_t nof_meas_data = meas_values.size(); - uint32_t nof_metrics = 1; - uint32_t nof_records = nof_metrics; + std::vector meas_real_values = {0.15625, 0.15625, 0.15625, 0.15625, 0.15625}; + std::vector meas_int_values = {1, 2, 3, 4, 5}; + uint32_t nof_meas_data = meas_real_values.size(); + uint32_t nof_metrics = 2; + uint32_t nof_records = nof_metrics; // Define E2SM_KPM action format 1. e2_sm_kpm_action_definition_s action_def; @@ -172,8 +202,10 @@ TEST_P(e2sm_kpm_indication, e2sm_kpm_generates_ric_indication_style1) asn1::e2ap::ri_caction_to_be_setup_item_s ric_action = generate_e2sm_kpm_ric_action(action_def); ASSERT_FALSE(e2sm_kpm_iface->action_supported(ric_action)); - action_def_f1.meas_info_list[0].meas_type.set_meas_name().from_string( - "DRB.RlcSduDelayDl"); // Change to a valid metric. + action_def_f1.meas_info_list[0].meas_type.set_meas_name().from_string("DRB.UEThpUl"); // Change to a valid metric. + + action_def_f1.meas_info_list.push_back(meas_info_item); // Add a second metric. + action_def_f1.meas_info_list[1].meas_type.set_meas_name().from_string("DRB.RlcSduDelayDl"); ric_action = generate_e2sm_kpm_ric_action(action_def); if (g_enable_pcap) { @@ -191,7 +223,8 @@ TEST_P(e2sm_kpm_indication, e2sm_kpm_generates_ric_indication_style1) for (unsigned i = 0; i < nof_meas_data; ++i) { // Push dummy metric measurements. - du_meas_provider->push_measurements_float({1}, {1}, {meas_values[i]}); + du_meas_provider->push_measurements_int({1}, {1}, {meas_int_values[i]}); + du_meas_provider->push_measurements_float({1}, {1}, {meas_real_values[i]}); // Trigger measurement collection. report_service->collect_measurements(); } @@ -212,8 +245,10 @@ TEST_P(e2sm_kpm_indication, e2sm_kpm_generates_ric_indication_style1) TESTASSERT_EQ(nof_meas_data, ric_ind_msg.ind_msg_formats.ind_msg_format1().meas_data.size()); for (unsigned i = 0; i < nof_meas_data; ++i) { TESTASSERT_EQ(nof_records, ric_ind_msg.ind_msg_formats.ind_msg_format1().meas_data[i].meas_record.size()); - TESTASSERT_EQ(meas_values[i], - ric_ind_msg.ind_msg_formats.ind_msg_format1().meas_data[i].meas_record[0].real().value); + TESTASSERT_EQ(meas_int_values[i], + ric_ind_msg.ind_msg_formats.ind_msg_format1().meas_data[i].meas_record[0].integer()); + TESTASSERT_EQ(meas_real_values[i], + ric_ind_msg.ind_msg_formats.ind_msg_format1().meas_data[i].meas_record[1].real().value); } if (g_enable_pcap) { @@ -748,6 +783,7 @@ TEST_P(e2sm_kpm_indication, e2sm_kpm_generates_ric_indication_style5) } } +INSTANTIATE_TEST_SUITE_P(e2sm_kpm_tests, e2_entity_test_with_pcap, testing::Values(g_pcap)); INSTANTIATE_TEST_SUITE_P(e2sm_kpm_tests, e2sm_kpm_indication, testing::Values(g_pcap)); int main(int argc, char** argv) From e74856a7f8abf9b9f7871c3ee8e3c4d93a41805f Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Fri, 23 Feb 2024 11:10:16 +0100 Subject: [PATCH 023/140] sched: fix allocation of PDSCH RBs for SRB data --- lib/scheduler/policy/scheduler_time_rr.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/scheduler/policy/scheduler_time_rr.cpp b/lib/scheduler/policy/scheduler_time_rr.cpp index b8dd739e96..0b1532f034 100644 --- a/lib/scheduler/policy/scheduler_time_rr.cpp +++ b/lib/scheduler/policy/scheduler_time_rr.cpp @@ -497,15 +497,15 @@ void scheduler_time_rr::dl_sched(ue_pdsch_allocator& pdsch_alloc, }; next_dl_ue_index = round_robin_apply(ues, next_dl_ue_index, retx_ue_function); + const unsigned dl_new_tx_max_nof_rbs_per_ue_per_slot = + compute_max_nof_rbs_per_ue_per_slot(ues, true, res_grid, expert_cfg); // Second, schedule UEs with SRB data. - auto srb_newtx_ue_function = [this, &res_grid, &pdsch_alloc](const ue& u) { - return alloc_dl_ue(u, res_grid, pdsch_alloc, false, true, logger); + auto srb_newtx_ue_function = [this, &res_grid, &pdsch_alloc, dl_new_tx_max_nof_rbs_per_ue_per_slot](const ue& u) { + return alloc_dl_ue(u, res_grid, pdsch_alloc, false, true, logger, dl_new_tx_max_nof_rbs_per_ue_per_slot); }; next_dl_ue_index = round_robin_apply(ues, next_dl_ue_index, srb_newtx_ue_function); // Then, schedule new transmissions. - const unsigned dl_new_tx_max_nof_rbs_per_ue_per_slot = - compute_max_nof_rbs_per_ue_per_slot(ues, true, res_grid, expert_cfg); if (dl_new_tx_max_nof_rbs_per_ue_per_slot > 0) { auto tx_ue_function = [this, &res_grid, &pdsch_alloc, dl_new_tx_max_nof_rbs_per_ue_per_slot](const ue& u) { return alloc_dl_ue(u, res_grid, pdsch_alloc, false, false, logger, dl_new_tx_max_nof_rbs_per_ue_per_slot); From 6c0da481db143b991f919f077c690deab1cb8db9 Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Fri, 23 Feb 2024 22:49:36 +0100 Subject: [PATCH 024/140] asn1_utils,fixed_octstring: fix for size = 8 --- lib/asn1/asn1_utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/asn1/asn1_utils.cpp b/lib/asn1/asn1_utils.cpp index 9a71bc0613..8e17170ff4 100644 --- a/lib/asn1/asn1_utils.cpp +++ b/lib/asn1/asn1_utils.cpp @@ -929,7 +929,7 @@ uint64_t octet_string_helper::to_uint(const byte_buffer& buf) void octet_string_helper::to_octet_string(srsran::span buf, uint64_t number) { uint64_t nbytes = buf.size(); - if ((static_cast(1U) << (8U * nbytes)) <= number) { + if (nbytes < 8 and (static_cast(1U) << (8U * nbytes)) <= number) { log_error("Integer={} does not fit in an OCTET STRING of size={}", number, nbytes); return; } From ecbaa1e0b85782e5db371de6547748121460ec6f Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Sat, 17 Feb 2024 17:30:54 +0100 Subject: [PATCH 025/140] sched: notify UE config changes to the UCI scheduler --- include/srsran/ran/csi_rs/csi_report_config.h | 3 + include/srsran/ran/sr_configuration.h | 3 + .../uci_scheduling/uci_scheduler_impl.cpp | 96 +++++++++++++++++++ .../uci_scheduling/uci_scheduler_impl.h | 16 ++++ .../ue_scheduling/ue_event_manager.cpp | 47 ++++++++- .../ue_scheduling/ue_event_manager.h | 8 +- .../ue_scheduling/ue_scheduler_impl.cpp | 2 +- 7 files changed, 170 insertions(+), 5 deletions(-) diff --git a/include/srsran/ran/csi_rs/csi_report_config.h b/include/srsran/ran/csi_rs/csi_report_config.h index 8f915f58f6..09387e7638 100644 --- a/include/srsran/ran/csi_rs/csi_report_config.h +++ b/include/srsran/ran/csi_rs/csi_report_config.h @@ -29,6 +29,9 @@ enum csi_report_config_id_t : uint8_t { MAX_NOF_CSI_REPORT_CONFIGS = 48, }; +/// Maximum CSI report period in slots. +constexpr unsigned MAX_CSI_REPORT_PERIOD = 320; + /// \brief Periodicity and slot offset. /// \remark See TS 38.331, \c CSI-ReportPeriodicityAndOffset. enum class csi_report_periodicity { diff --git a/include/srsran/ran/sr_configuration.h b/include/srsran/ran/sr_configuration.h index 8dbe817fcd..16a46057b9 100644 --- a/include/srsran/ran/sr_configuration.h +++ b/include/srsran/ran/sr_configuration.h @@ -29,6 +29,9 @@ inline scheduling_request_id uint_to_sched_req_id(unsigned sr_id) return static_cast(sr_id); } +/// Maximum SR period in slots. +constexpr unsigned MAX_SR_PERIOD = 640; + /// Encodes the periodicity (only) of \c periodicityAndOffset for \c SchedulingRequestResourceConfig, TS 38.331. Note /// that the offset is encoded separately. enum class sr_periodicity : int { diff --git a/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp b/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp index 8ad0eab137..858141e55c 100644 --- a/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp +++ b/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp @@ -21,6 +21,8 @@ uci_scheduler_impl::uci_scheduler_impl(const cell_configuration& cell_cfg_, ue_repository& ues_) : cell_cfg(cell_cfg_), uci_alloc(uci_alloc_), ues(ues_), logger(srslog::fetch_basic_logger("SCHED")) { + // Max size of the UCI resource slot wheel, dimensioned based on the UCI periods. + periodic_uci_slot_wheel.resize(std::max(MAX_SR_PERIOD, MAX_CSI_REPORT_PERIOD)); } uci_scheduler_impl::~uci_scheduler_impl() = default; @@ -65,6 +67,100 @@ void uci_scheduler_impl::run_slot(cell_resource_allocator& cell_alloc, slot_poin } } +void uci_scheduler_impl::add_ue(const ue_cell_configuration& ue_cfg) +{ + if (not ue_cfg.cfg_dedicated().ul_config.has_value() or + not ue_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.has_value()) { + return; + } + + // Save SR resources in the slot wheel. + const auto& sr_resource_cfg_list = ue_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.value().sr_res_list; + for (unsigned i = 0; i != sr_resource_cfg_list.size(); ++i) { + const auto& sr_res = sr_resource_cfg_list[i]; + srsran_assert(sr_res.period >= sr_periodicity::sl_1, "Minimum supported SR periodicity is 1 slot."); + + unsigned period_slots = sr_periodicity_to_slot(sr_res.period); + for (unsigned offset = sr_res.offset; offset < periodic_uci_slot_wheel.size(); offset += period_slots) { + periodic_uci_slot_wheel[offset].push_back(periodic_uci_info{ue_cfg.crnti, true, i}); + } + } + + if (ue_cfg.cfg_dedicated().csi_meas_cfg.has_value()) { + // We assume we only use the first CSI report configuration. + const unsigned csi_report_cfg_idx = 0; + const auto& csi_report_cfg = ue_cfg.cfg_dedicated().csi_meas_cfg.value().csi_report_cfg_list[csi_report_cfg_idx]; + const auto& period_pucch = + variant_get(csi_report_cfg.report_cfg_type); + + unsigned period_slots = csi_report_periodicity_to_uint(period_pucch.report_slot_period); + for (unsigned offset = period_pucch.report_slot_offset; offset < periodic_uci_slot_wheel.size(); + offset += period_slots) { + periodic_uci_slot_wheel[offset].push_back(periodic_uci_info{ue_cfg.crnti, false, 0}); + } + } +} + +void uci_scheduler_impl::reconf_ue(const ue_cell_configuration& new_ue_cfg, const ue_cell_configuration& old_ue_cfg) +{ + // Detect differences. + if (new_ue_cfg.cfg_dedicated().ul_config.has_value() and old_ue_cfg.cfg_dedicated().ul_config.has_value() and + new_ue_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.has_value() and + old_ue_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.has_value()) { + // Both old and new UE config have PUCCH config. + const auto& new_pucch = new_ue_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.value(); + const auto& old_pucch = old_ue_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.value(); + + if (new_pucch.sr_res_list == old_pucch.sr_res_list and + new_ue_cfg.cfg_dedicated().csi_meas_cfg == old_ue_cfg.cfg_dedicated().csi_meas_cfg) { + // Nothing changed. + return; + } + } + + rem_ue(old_ue_cfg); + add_ue(new_ue_cfg); +} + +void uci_scheduler_impl::rem_ue(const ue_cell_configuration& ue_cfg) +{ + if (not ue_cfg.cfg_dedicated().ul_config.has_value() or + not ue_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.has_value()) { + return; + } + + const auto& sr_resource_cfg_list = ue_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.value().sr_res_list; + for (unsigned i = 0; i != sr_resource_cfg_list.size(); ++i) { + const auto& sr_res = sr_resource_cfg_list[i]; + + unsigned period_slots = sr_periodicity_to_slot(sr_res.period); + for (unsigned offset = sr_res.offset; offset < periodic_uci_slot_wheel.size(); offset += period_slots) { + // Removing without keeping order as it is not relevant. + auto rem_it = std::remove_if(periodic_uci_slot_wheel[offset].begin(), + periodic_uci_slot_wheel[offset].end(), + [&ue_cfg](const auto& e) { return e.rnti == ue_cfg.crnti; }); + periodic_uci_slot_wheel[offset].erase(rem_it, periodic_uci_slot_wheel[offset].end()); + } + } + + if (ue_cfg.cfg_dedicated().csi_meas_cfg.has_value()) { + // We assume we only use the first CSI report configuration. + const unsigned csi_report_cfg_idx = 0; + const auto& csi_report_cfg = ue_cfg.cfg_dedicated().csi_meas_cfg.value().csi_report_cfg_list[csi_report_cfg_idx]; + const auto& period_pucch = + variant_get(csi_report_cfg.report_cfg_type); + + unsigned period_slots = csi_report_periodicity_to_uint(period_pucch.report_slot_period); + for (unsigned offset = period_pucch.report_slot_offset; offset < periodic_uci_slot_wheel.size(); + offset += period_slots) { + auto rem_it = std::remove_if(periodic_uci_slot_wheel[offset].begin(), + periodic_uci_slot_wheel[offset].end(), + [&ue_cfg](const auto& e) { return e.rnti == ue_cfg.crnti; }); + periodic_uci_slot_wheel[offset].erase(rem_it, periodic_uci_slot_wheel[offset].end()); + } + } +} + void uci_scheduler_impl::schedule_uci(cell_slot_resource_allocator& slot_alloc, rnti_t crnti, const ue_cell& user, diff --git a/lib/scheduler/uci_scheduling/uci_scheduler_impl.h b/lib/scheduler/uci_scheduling/uci_scheduler_impl.h index e9aaaea81e..e164cf6260 100644 --- a/lib/scheduler/uci_scheduling/uci_scheduler_impl.h +++ b/lib/scheduler/uci_scheduling/uci_scheduler_impl.h @@ -30,7 +30,20 @@ class uci_scheduler_impl final : public uci_scheduler void run_slot(cell_resource_allocator& res_alloc, slot_point sl_tx) override; + void add_ue(const ue_cell_configuration& ue_cfg); + + void reconf_ue(const ue_cell_configuration& new_ue_cfg, const ue_cell_configuration& old_ue_cfg); + + void rem_ue(const ue_cell_configuration& ue_cfg); + private: + /// Information on currently configured UE UCI resource to periodically schedule. + struct periodic_uci_info { + rnti_t rnti; + bool is_sr; + unsigned res_idx; + }; + // Helper that schedules the SR and CSI for a given user at a given slot. void schedule_uci(cell_slot_resource_allocator& slot_alloc, rnti_t crnti, @@ -44,6 +57,9 @@ class uci_scheduler_impl final : public uci_scheduler ue_repository& ues; srslog::basic_logger& logger; + + // Storage of the periodic UCIs to be scheduled in the resource grid. + std::vector> periodic_uci_slot_wheel; }; } // namespace srsran diff --git a/lib/scheduler/ue_scheduling/ue_event_manager.cpp b/lib/scheduler/ue_scheduling/ue_event_manager.cpp index 4c251ce673..7f0acfd9e4 100644 --- a/lib/scheduler/ue_scheduling/ue_event_manager.cpp +++ b/lib/scheduler/ue_scheduling/ue_event_manager.cpp @@ -12,6 +12,7 @@ #include "../config/sched_config_manager.h" #include "../logging/scheduler_event_logger.h" #include "../logging/scheduler_metrics_handler.h" +#include "../uci_scheduling/uci_scheduler_impl.h" using namespace srsran; @@ -144,6 +145,12 @@ void ue_event_manager::handle_ue_creation(ue_config_update_event ev) du_cell_index_t pcell_index = u->get_pcell().cell_index; ue_db.add_ue(std::move(u)); + // Update UCI scheduler with new UE UCI resources. + const auto& added_ue = ue_db[ueidx]; + for (unsigned i = 0; i != added_ue.nof_cells(); ++i) { + du_cells[pcell_index].uci_sched->add_ue(added_ue.get_cell(to_ue_cell_index(i)).cfg()); + } + // Log Event. ev_logger.enqueue(scheduler_event_logger::ue_creation_event{ueidx, rnti, pcell_index}); }); @@ -159,10 +166,37 @@ void ue_event_manager::handle_ue_reconfiguration(ue_config_update_event ev) ev.abort(); return; } + auto& u = ue_db[ue_idx]; + + // Update UE UCI resources in UCI scheduler. + for (unsigned i = 0; i != u.nof_cells(); ++i) { + auto& ue_cc = u.get_cell(to_ue_cell_index(i)); + if (not ev.next_config().contains(ue_cc.cell_index)) { + // UE carrier is being removed. + du_cells[ue_cc.cell_index].uci_sched->rem_ue(ue_cc.cfg()); + } else { + // UE carrier is being reconfigured. + du_cells[ue_cc.cell_index].uci_sched->reconf_ue(ev.next_config().ue_cell_cfg(ue_cc.cell_index), ue_cc.cfg()); + } + } + for (unsigned i = 0; i != ev.next_config().nof_cells(); ++i) { + auto& new_ue_cc_cfg = ev.next_config().ue_cell_cfg(to_ue_cell_index(i)); + auto* ue_cc = u.find_cell(new_ue_cc_cfg.cell_cfg_common.cell_index); + if (ue_cc == nullptr) { + // new UE carrier is being added. + du_cells[new_ue_cc_cfg.cell_cfg_common.cell_index].uci_sched->add_ue(new_ue_cc_cfg); + } + } // Configure existing UE. ue_db[ue_idx].handle_reconfiguration_request(ue_reconf_command{ev.next_config()}); + // Update UCI scheduler with new resources. + for (unsigned i = 0; i != u.nof_cells(); ++i) { + auto& ue_cc = u.get_cell(to_ue_cell_index(i)); + du_cells[ue_cc.cell_index].uci_sched->rem_ue(ue_cc.cfg()); + } + // Log event. ev_logger.enqueue(scheduler_event_logger::ue_reconf_event{ue_idx, ue_db[ue_idx].crnti}); }); @@ -177,7 +211,13 @@ void ue_event_manager::handle_ue_deletion(ue_config_delete_event ev) logger.warning("Received request to delete ue={} that does not exist", ue_idx); return; } - const rnti_t rnti = ue_db[ue_idx].crnti; + const auto& u = ue_db[ue_idx]; + const rnti_t rnti = u.crnti; + + // Update UCI scheduling by removing existing UE UCI resources. + for (unsigned i = 0; i != u.nof_cells(); ++i) { + du_cells[u.get_cell(to_ue_cell_index(i)).cell_index].uci_sched->rem_ue(u.get_pcell().cfg()); + } // Scheduler UE removal from repository. ue_db.schedule_ue_rem(std::move(ev)); @@ -603,7 +643,9 @@ void ue_event_manager::run(slot_point sl, du_cell_index_t cell_index) process_cell_specific(cell_index); } -void ue_event_manager::add_cell(cell_resource_allocator& cell_res_grid, ue_srb0_scheduler& srb0_sched) +void ue_event_manager::add_cell(cell_resource_allocator& cell_res_grid, + ue_srb0_scheduler& srb0_sched, + uci_scheduler_impl& uci_sched) { const du_cell_index_t cell_index = cell_res_grid.cell_index(); srsran_assert(not cell_exists(cell_index), "Overwriting cell configurations not supported"); @@ -611,6 +653,7 @@ void ue_event_manager::add_cell(cell_resource_allocator& cell_res_grid, ue_srb0_ du_cells[cell_index].cfg = &cell_res_grid.cfg; du_cells[cell_index].res_grid = &cell_res_grid; du_cells[cell_index].srb0_sched = &srb0_sched; + du_cells[cell_index].uci_sched = &uci_sched; } bool ue_event_manager::cell_exists(du_cell_index_t cell_index) const diff --git a/lib/scheduler/ue_scheduling/ue_event_manager.h b/lib/scheduler/ue_scheduling/ue_event_manager.h index b3aee0445e..15ce777064 100644 --- a/lib/scheduler/ue_scheduling/ue_event_manager.h +++ b/lib/scheduler/ue_scheduling/ue_event_manager.h @@ -23,6 +23,7 @@ namespace srsran { class scheduler_metrics_handler; class scheduler_event_logger; +class uci_scheduler_impl; /// \brief Class used to manage events that arrive to the scheduler and are directed at UEs. /// This class acts as a facade for several of the ue_scheduler subcomponents, managing the asynchronous configuration @@ -35,7 +36,7 @@ class ue_event_manager final : public sched_ue_configuration_handler, ue_event_manager(ue_repository& ue_db, scheduler_metrics_handler& metrics_handler, scheduler_event_logger& ev_logger); ~ue_event_manager(); - void add_cell(cell_resource_allocator& cell_res_grid, ue_srb0_scheduler& srb0_sched); + void add_cell(cell_resource_allocator& cell_res_grid, ue_srb0_scheduler& srb0_sched, uci_scheduler_impl& uci_sched); /// UE Add/Mod/Remove interface. void handle_ue_creation(ue_config_update_event ev) override; @@ -111,8 +112,11 @@ class ue_event_manager final : public sched_ue_configuration_handler, cell_resource_allocator* res_grid = nullptr; - /// Reference to SRB0 and other bearers scheduler + // Reference to SRB0 and other bearers scheduler ue_srb0_scheduler* srb0_sched = nullptr; + + // Reference to the CSI and SR UCI scheduler. + uci_scheduler_impl* uci_sched = nullptr; }; std::array du_cells{}; diff --git a/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp b/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp index d4012fdc6b..977d57e003 100644 --- a/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp +++ b/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp @@ -30,7 +30,7 @@ void ue_scheduler_impl::add_cell(const ue_scheduler_cell_params& params) { ue_res_grid_view.add_cell(*params.cell_res_alloc); cells[params.cell_index] = std::make_unique(expert_cfg, params, ue_db); - event_mng.add_cell(*params.cell_res_alloc, cells[params.cell_index]->srb0_sched); + event_mng.add_cell(*params.cell_res_alloc, cells[params.cell_index]->srb0_sched, cells[params.cell_index]->uci_sched); ue_alloc.add_cell(params.cell_index, *params.pdcch_sched, *params.uci_alloc, *params.cell_res_alloc); } From ece69742a403a6aa38186dc73e8f01b9ca1f0300 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Sat, 17 Feb 2024 19:59:11 +0100 Subject: [PATCH 026/140] sched: use timer wheel for UCI periodic scheduling --- lib/scheduler/uci_scheduling/uci_scheduler.h | 3 +- .../uci_scheduling/uci_scheduler_impl.cpp | 141 +++++++++++------- .../uci_scheduling/uci_scheduler_impl.h | 21 +-- lib/scheduler/ue_scheduling/ue_cell.h | 6 - .../ue_scheduling/ue_scheduler_impl.cpp | 2 +- .../uci_and_pucch/uci_scheduling_test.cpp | 4 +- 6 files changed, 100 insertions(+), 77 deletions(-) diff --git a/lib/scheduler/uci_scheduling/uci_scheduler.h b/lib/scheduler/uci_scheduling/uci_scheduler.h index 4a74057c2a..b7f89dbcde 100644 --- a/lib/scheduler/uci_scheduling/uci_scheduler.h +++ b/lib/scheduler/uci_scheduling/uci_scheduler.h @@ -22,8 +22,7 @@ class uci_scheduler /// Schedules the SR opportunities and CSI occasions. /// \param[out,in] res_alloc struct with scheduling results. - /// \param[in] sl_tx slot for which the SR should be allocated. - virtual void run_slot(cell_resource_allocator& res_alloc, slot_point sl_tx) = 0; + virtual void run_slot(cell_resource_allocator& res_alloc) = 0; }; } // namespace srsran diff --git a/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp b/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp index 858141e55c..72285c7d51 100644 --- a/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp +++ b/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp @@ -23,48 +23,21 @@ uci_scheduler_impl::uci_scheduler_impl(const cell_configuration& cell_cfg_, { // Max size of the UCI resource slot wheel, dimensioned based on the UCI periods. periodic_uci_slot_wheel.resize(std::max(MAX_SR_PERIOD, MAX_CSI_REPORT_PERIOD)); + + // Pre-reserve space for the UEs that will be added. + updated_ues.reserve(MAX_NOF_DU_UES); } uci_scheduler_impl::~uci_scheduler_impl() = default; -void uci_scheduler_impl::run_slot(cell_resource_allocator& cell_alloc, slot_point sl_tx) +void uci_scheduler_impl::run_slot(cell_resource_allocator& cell_alloc) { - for (auto& user : ues) { - // At this point, we assume the config validator ensures there is pCell. - auto& ue_cell = user->get_pcell(); - - if (not ue_cell.is_active() or not ue_cell.cfg().cfg_dedicated().ul_config.has_value()) { - continue; - } + // Initial allocation: we allocate opportunities all over the grid. + schedule_updated_ues_ucis(cell_alloc); - optional> csi_period_and_offset; - if (ue_cell.cfg().cfg_dedicated().csi_meas_cfg.has_value()) { - // We assume we only use the first CSI report configuration. - const unsigned csi_report_cfg_idx = 0; - const auto& csi_report_cfg = - ue_cell.cfg().cfg_dedicated().csi_meas_cfg.value().csi_report_cfg_list[csi_report_cfg_idx]; - - csi_period_and_offset.emplace(std::pair{ - csi_report_periodicity_to_uint(variant_get( - csi_report_cfg.report_cfg_type) - .report_slot_period), - variant_get(csi_report_cfg.report_cfg_type) - .report_slot_offset}); - } - - if (ue_cell.is_pucch_grid_inited()) { - // Only allocate in the farthest slot in the grid, as the previous part of the allocation grid has been completed - // at the first this function was called. - schedule_uci(cell_alloc[cell_alloc.max_ul_slot_alloc_delay], user->crnti, ue_cell, csi_period_and_offset); - } - // Initial allocation: we allocate opportunities all over the grid. - else { - for (unsigned n = 0; n != cell_alloc.max_ul_slot_alloc_delay + 1; ++n) { - schedule_uci(cell_alloc[n], user->crnti, ue_cell, csi_period_and_offset); - } - ue_cell.set_pucch_grid_inited(); - } - } + // Only allocate in the farthest slot in the grid, as the previous part of the allocation grid has been completed + // at the first this function was called. + schedule_slot_ucis(cell_alloc[cell_alloc.max_ul_slot_alloc_delay]); } void uci_scheduler_impl::add_ue(const ue_cell_configuration& ue_cfg) @@ -82,7 +55,7 @@ void uci_scheduler_impl::add_ue(const ue_cell_configuration& ue_cfg) unsigned period_slots = sr_periodicity_to_slot(sr_res.period); for (unsigned offset = sr_res.offset; offset < periodic_uci_slot_wheel.size(); offset += period_slots) { - periodic_uci_slot_wheel[offset].push_back(periodic_uci_info{ue_cfg.crnti, true, i}); + periodic_uci_slot_wheel[offset].push_back(periodic_uci_info{ue_cfg.crnti, true}); } } @@ -96,9 +69,12 @@ void uci_scheduler_impl::add_ue(const ue_cell_configuration& ue_cfg) unsigned period_slots = csi_report_periodicity_to_uint(period_pucch.report_slot_period); for (unsigned offset = period_pucch.report_slot_offset; offset < periodic_uci_slot_wheel.size(); offset += period_slots) { - periodic_uci_slot_wheel[offset].push_back(periodic_uci_info{ue_cfg.crnti, false, 0}); + periodic_uci_slot_wheel[offset].push_back(periodic_uci_info{ue_cfg.crnti, false}); } } + + // Register the UE in the list of recently configured UEs. + updated_ues.push_back(ue_cfg.crnti); } void uci_scheduler_impl::reconf_ue(const ue_cell_configuration& new_ue_cfg, const ue_cell_configuration& old_ue_cfg) @@ -161,33 +137,84 @@ void uci_scheduler_impl::rem_ue(const ue_cell_configuration& ue_cfg) } } -void uci_scheduler_impl::schedule_uci(cell_slot_resource_allocator& slot_alloc, - rnti_t crnti, - const ue_cell& user, - optional> csi_period_and_offset) +const ue_cell_configuration* uci_scheduler_impl::get_ue_cfg(rnti_t rnti) const { - if (not cell_cfg.is_fully_ul_enabled(slot_alloc.slot)) { - return; + auto* u = ues.find_by_rnti(rnti); + if (u != nullptr) { + auto* ue_cc = u->find_cell(cell_cfg.cell_index); + if (ue_cc != nullptr) { + return &ue_cc->cfg(); + } } + return nullptr; +} - // At this point, we assume the UE has a \c ul_config, a \c pucch_cfg and a \c sr_res_list. - const auto& sr_resource_cfg_list = - user.cfg().cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.value().sr_res_list; - +void uci_scheduler_impl::schedule_slot_ucis(cell_slot_resource_allocator& slot_alloc) +{ + // For the provided slot, check if there are any pending UCI resources to allocate, and allocate them. // NOTE: Allocating the CSI after the SR helps the PUCCH allocation to compute the number of allocated UCI bits and // the corresponding number of PRBs for the PUCCH Format 2 over a PUCCH F2 grant is within PUCCH capacity. - - for (const auto& sr_res : sr_resource_cfg_list) { - srsran_assert(sr_res.period >= sr_periodicity::sl_1, "Minimum supported SR periodicity is 1 slot."); - - if ((slot_alloc.slot - sr_res.offset).to_uint() % sr_periodicity_to_slot(sr_res.period) == 0) { - uci_alloc.uci_allocate_sr_opportunity(slot_alloc, crnti, user.cfg()); + auto& slot_ucis = periodic_uci_slot_wheel[slot_alloc.slot.to_uint() % periodic_uci_slot_wheel.size()]; + for (const periodic_uci_info& uci_info : slot_ucis) { + if (uci_info.is_sr) { + auto* ue_cfg = get_ue_cfg(uci_info.rnti); + if (ue_cfg != nullptr) { + uci_alloc.uci_allocate_sr_opportunity(slot_alloc, uci_info.rnti, *ue_cfg); + } else { + logger.error("UE with RNTI {} and cell={} not found.", uci_info.rnti, cell_cfg.cell_index); + } } } + for (const periodic_uci_info& uci_info : slot_ucis) { + if (not uci_info.is_sr) { + auto* ue_cfg = get_ue_cfg(uci_info.rnti); + if (ue_cfg != nullptr) { + uci_alloc.uci_allocate_csi_opportunity(slot_alloc, uci_info.rnti, *ue_cfg); + } else { + logger.error("UE with RNTI {} and cell={} not found.", uci_info.rnti, cell_cfg.cell_index); + } + } + } +} - if (csi_period_and_offset.has_value()) { - if ((slot_alloc.slot - csi_period_and_offset->second).to_uint() % csi_period_and_offset->first == 0) { - uci_alloc.uci_allocate_csi_opportunity(slot_alloc, crnti, user.cfg()); +void uci_scheduler_impl::schedule_updated_ues_ucis(cell_resource_allocator& cell_alloc) +{ + // For all UEs whose config has been recently updated, schedule their UCIs up until one slot before the farthest + // slot in the resource grid. + // TODO: Remove UCIs from the list of updated UEs when the UE is removed, if they have no HARQ-ACK. + for (rnti_t rnti : updated_ues) { + auto* ue_cfg = get_ue_cfg(rnti); + if (ue_cfg == nullptr) { + logger.error("UE with RNTI {} and cell={} not found.", rnti, cell_cfg.cell_index); + continue; + } + + // Schedule UCI up to the farthest slot. + for (unsigned n = 0; n != cell_alloc.max_ul_slot_alloc_delay; ++n) { + auto& slot_ucis = periodic_uci_slot_wheel[(cell_alloc.slot_tx() + n).to_uint() % periodic_uci_slot_wheel.size()]; + + // Schedule SRs first + // NOTE: Allocating the CSI after the SR helps the PUCCH allocation to compute the number of allocated UCI bits + // and the corresponding number of PRBs for the PUCCH Format 2 over a PUCCH F2 grant is within PUCCH capacity. + for (const periodic_uci_info& uci_info : slot_ucis) { + if (uci_info.rnti == rnti) { + if (uci_info.is_sr) { + uci_alloc.uci_allocate_sr_opportunity(cell_alloc[n], rnti, *ue_cfg); + } + } + } + + // Schedule CSI + for (const periodic_uci_info& uci_info : slot_ucis) { + if (uci_info.rnti == rnti) { + if (not uci_info.is_sr) { + uci_alloc.uci_allocate_csi_opportunity(cell_alloc[n], rnti, *ue_cfg); + } + } + } } } + + // Clear the list of updated UEs. + updated_ues.clear(); } diff --git a/lib/scheduler/uci_scheduling/uci_scheduler_impl.h b/lib/scheduler/uci_scheduling/uci_scheduler_impl.h index e164cf6260..7e563eda65 100644 --- a/lib/scheduler/uci_scheduling/uci_scheduler_impl.h +++ b/lib/scheduler/uci_scheduling/uci_scheduler_impl.h @@ -28,7 +28,7 @@ class uci_scheduler_impl final : public uci_scheduler ~uci_scheduler_impl() override; - void run_slot(cell_resource_allocator& res_alloc, slot_point sl_tx) override; + void run_slot(cell_resource_allocator& res_alloc) override; void add_ue(const ue_cell_configuration& ue_cfg); @@ -39,16 +39,16 @@ class uci_scheduler_impl final : public uci_scheduler private: /// Information on currently configured UE UCI resource to periodically schedule. struct periodic_uci_info { - rnti_t rnti; - bool is_sr; - unsigned res_idx; + rnti_t rnti; + bool is_sr; }; - // Helper that schedules the SR and CSI for a given user at a given slot. - void schedule_uci(cell_slot_resource_allocator& slot_alloc, - rnti_t crnti, - const ue_cell& user, - optional> csi_period_and_offset); + // Helper to fetch a UE cell config. + const ue_cell_configuration* get_ue_cfg(rnti_t rnti) const; + // Helper that schedules the SR and CSI for a given slot. + void schedule_slot_ucis(cell_slot_resource_allocator& slot_alloc); + // Helper that schedules the SR and CSI for UEs that were recently updated. + void schedule_updated_ues_ucis(cell_resource_allocator& res_alloc); // Cell configuration. const cell_configuration& cell_cfg; @@ -60,6 +60,9 @@ class uci_scheduler_impl final : public uci_scheduler // Storage of the periodic UCIs to be scheduled in the resource grid. std::vector> periodic_uci_slot_wheel; + + // UEs whose configuration has been updated in between the last and current slot indications. + std::vector updated_ues; }; } // namespace srsran diff --git a/lib/scheduler/ue_scheduling/ue_cell.h b/lib/scheduler/ue_scheduling/ue_cell.h index 1bcb9e4610..3e73b7e4cc 100644 --- a/lib/scheduler/ue_scheduling/ue_cell.h +++ b/lib/scheduler/ue_scheduling/ue_cell.h @@ -122,10 +122,6 @@ class ue_cell is_fallback_mode = fallback_state_; } - bool is_pucch_grid_inited() const { return is_pucch_alloc_grid_initialized; } - - void set_pucch_grid_inited() { is_pucch_alloc_grid_initialized = true; } - /// \brief Get UE channel state handler. ue_channel_state_manager& channel_state_manager() { return channel_state; } const ue_channel_state_manager& channel_state_manager() const { return channel_state; } @@ -150,8 +146,6 @@ class ue_cell /// already have applied a dedicated config. bool is_fallback_mode = false; - bool is_pucch_alloc_grid_initialized = false; - metrics ue_metrics; ue_channel_state_manager channel_state; diff --git a/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp b/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp index 977d57e003..72928a04a0 100644 --- a/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp +++ b/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp @@ -152,7 +152,7 @@ void ue_scheduler_impl::run_slot(slot_point slot_tx, du_cell_index_t cell_index) ue_alloc.slot_indication(); // Schedule periodic UCI (SR and CSI) before any UL grants. - cells[cell_index]->uci_sched.run_slot(*cells[cell_index]->cell_res_alloc, slot_tx); + cells[cell_index]->uci_sched.run_slot(*cells[cell_index]->cell_res_alloc); // Run cell-specific SRB0 scheduler. cells[cell_index]->srb0_sched.run_slot(*cells[cell_index]->cell_res_alloc); diff --git a/tests/unittests/scheduler/uci_and_pucch/uci_scheduling_test.cpp b/tests/unittests/scheduler/uci_and_pucch/uci_scheduling_test.cpp index 19b68c4b3f..4d4efa39ab 100644 --- a/tests/unittests/scheduler/uci_and_pucch/uci_scheduling_test.cpp +++ b/tests/unittests/scheduler/uci_and_pucch/uci_scheduling_test.cpp @@ -106,7 +106,7 @@ TEST_P(uci_sr_scheduler_tester, test_different_periods) // Randomize initial slot, as the UCI scheduler will be called only after the UE is added. const unsigned starting_slot = test_rgen::uniform_int(0, 1000U); for (unsigned sl_cnt = starting_slot; sl_cnt < starting_slot + NOF_SLOTS_TO_TEST; ++sl_cnt) { - t_bench.uci_sched.run_slot(t_bench.res_grid, t_bench.sl_tx); + t_bench.uci_sched.run_slot(t_bench.res_grid); if ((t_bench.sl_tx - sr_offset).to_uint() % sr_periodicity_to_slot(sr_period) == 0) { ASSERT_EQ(1, t_bench.res_grid[0].result.ul.pucchs.size()); // The scheduler allocates: @@ -219,7 +219,7 @@ TEST_P(uci_csi_scheduler_tester, test_different_periods) // Randomize initial slot, as the UCI scheduler will be called only after the UE is added. const unsigned starting_slot = test_rgen::uniform_int(0, 1000U); for (unsigned sl_cnt = starting_slot; sl_cnt < starting_slot + NOF_SLOTS_TO_TEST; ++sl_cnt) { - t_bench.uci_sched.run_slot(t_bench.res_grid, t_bench.sl_tx); + t_bench.uci_sched.run_slot(t_bench.res_grid); if ((t_bench.sl_tx - csi_offset).to_uint() % csi_report_periodicity_to_uint(csi_period) == 0) { ASSERT_EQ(1, t_bench.res_grid[0].result.ul.pucchs.size()); // The scheduler allocates: From 4b57ca868b972512331904221dadfb0b44d6193f Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 19 Feb 2024 10:58:47 +0100 Subject: [PATCH 027/140] sched: fix failing unit tests due to uci scheduler changes --- tests/unittests/scheduler/multiple_ue_sched_test.cpp | 6 +++--- tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/unittests/scheduler/multiple_ue_sched_test.cpp b/tests/unittests/scheduler/multiple_ue_sched_test.cpp index f1ecc7dd7f..263998abb9 100644 --- a/tests/unittests/scheduler/multiple_ue_sched_test.cpp +++ b/tests/unittests/scheduler/multiple_ue_sched_test.cpp @@ -229,9 +229,9 @@ class scheduler_impl_tester variant_get( ue_creation_req.cfg.cells.value()[0].serv_cell_cfg.csi_meas_cfg->csi_report_cfg_list[0].report_cfg_type) .report_slot_period); - if (params.tdd_ul_dl_cfg_common.has_value()) { + if (bench->cell_cfg.tdd_cfg_common.has_value()) { optional slot_offset = - find_next_tdd_full_ul_slot(params.tdd_ul_dl_cfg_common.value(), last_csi_report_offset + 1); + find_next_tdd_full_ul_slot(bench->cell_cfg.tdd_cfg_common.value(), last_csi_report_offset + 1); srsran_assert(slot_offset.has_value(), "Unable to find a valid CSI report slot offset UE={}", ue_index); srsran_assert(slot_offset.value() < csi_report_period_slots, "Unable to find a valid CSI report slot offset UE={}", @@ -566,7 +566,7 @@ struct multiple_ue_test_params { class multiple_ue_sched_tester : public scheduler_impl_tester, public ::testing::TestWithParam { public: - multiple_ue_sched_tester() : params{GetParam()} {}; + multiple_ue_sched_tester() : params{GetParam()} {} protected: multiple_ue_test_params params; diff --git a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp index 41c8bd92d7..36be70c310 100644 --- a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp +++ b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp @@ -183,6 +183,7 @@ test_bench::test_bench(const test_bench_params& params, ue_ded_cfgs.push_back(std::make_unique(ue_req.ue_index, ue_req.crnti, cell_cfg_list, ue_req.cfg)); ues.add_ue( std::make_unique(ue_creation_command{*ue_ded_cfgs.back(), ue_req.starts_in_fallback, harq_timeout_handler})); + uci_sched.add_ue(ues[ue_req.ue_index].get_pcell().cfg()); last_allocated_rnti = ue_req.crnti; last_allocated_ue_idx = main_ue_idx; slot_indication(sl_tx); From 78978c577c998b46dd8615628fdfe4a3f47514c6 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 19 Feb 2024 11:06:02 +0100 Subject: [PATCH 028/140] sched: remove pucch resource in uci scheduler if UE was deleted --- .../uci_scheduling/uci_scheduler_impl.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp b/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp index 72285c7d51..957d575d49 100644 --- a/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp +++ b/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp @@ -79,7 +79,7 @@ void uci_scheduler_impl::add_ue(const ue_cell_configuration& ue_cfg) void uci_scheduler_impl::reconf_ue(const ue_cell_configuration& new_ue_cfg, const ue_cell_configuration& old_ue_cfg) { - // Detect differences. + // Detect whether there are any differences in the old and new UE cell config. if (new_ue_cfg.cfg_dedicated().ul_config.has_value() and old_ue_cfg.cfg_dedicated().ul_config.has_value() and new_ue_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.has_value() and old_ue_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.has_value()) { @@ -155,25 +155,31 @@ void uci_scheduler_impl::schedule_slot_ucis(cell_slot_resource_allocator& slot_a // NOTE: Allocating the CSI after the SR helps the PUCCH allocation to compute the number of allocated UCI bits and // the corresponding number of PRBs for the PUCCH Format 2 over a PUCCH F2 grant is within PUCCH capacity. auto& slot_ucis = periodic_uci_slot_wheel[slot_alloc.slot.to_uint() % periodic_uci_slot_wheel.size()]; - for (const periodic_uci_info& uci_info : slot_ucis) { + for (auto it = slot_ucis.begin(); it != slot_ucis.end();) { + const periodic_uci_info& uci_info = *it; if (uci_info.is_sr) { - auto* ue_cfg = get_ue_cfg(uci_info.rnti); + const ue_cell_configuration* ue_cfg = get_ue_cfg(uci_info.rnti); if (ue_cfg != nullptr) { uci_alloc.uci_allocate_sr_opportunity(slot_alloc, uci_info.rnti, *ue_cfg); } else { logger.error("UE with RNTI {} and cell={} not found.", uci_info.rnti, cell_cfg.cell_index); + it = slot_ucis.erase(it); } } + ++it; } - for (const periodic_uci_info& uci_info : slot_ucis) { + for (auto it = slot_ucis.begin(); it != slot_ucis.end();) { + const periodic_uci_info& uci_info = *it; if (not uci_info.is_sr) { - auto* ue_cfg = get_ue_cfg(uci_info.rnti); + const ue_cell_configuration* ue_cfg = get_ue_cfg(uci_info.rnti); if (ue_cfg != nullptr) { uci_alloc.uci_allocate_csi_opportunity(slot_alloc, uci_info.rnti, *ue_cfg); } else { logger.error("UE with RNTI {} and cell={} not found.", uci_info.rnti, cell_cfg.cell_index); + it = slot_ucis.erase(it); } } + ++it; } } @@ -183,7 +189,7 @@ void uci_scheduler_impl::schedule_updated_ues_ucis(cell_resource_allocator& cell // slot in the resource grid. // TODO: Remove UCIs from the list of updated UEs when the UE is removed, if they have no HARQ-ACK. for (rnti_t rnti : updated_ues) { - auto* ue_cfg = get_ue_cfg(rnti); + const ue_cell_configuration* ue_cfg = get_ue_cfg(rnti); if (ue_cfg == nullptr) { logger.error("UE with RNTI {} and cell={} not found.", rnti, cell_cfg.cell_index); continue; From 8ff70567267dc4a575b415d5c009cf2a8e7ab0eb Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 20 Feb 2024 15:14:52 +0100 Subject: [PATCH 029/140] sched: change how UCI resources in the UCI scheduler are handled to leverage reference counting --- .../uci_scheduling/uci_scheduler_impl.cpp | 154 +++++++++++------- .../uci_scheduling/uci_scheduler_impl.h | 12 +- .../ue_scheduling/ue_event_manager.cpp | 3 +- 3 files changed, 109 insertions(+), 60 deletions(-) diff --git a/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp b/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp index 957d575d49..5fdbd39a35 100644 --- a/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp +++ b/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp @@ -40,6 +40,73 @@ void uci_scheduler_impl::run_slot(cell_resource_allocator& cell_alloc) schedule_slot_ucis(cell_alloc[cell_alloc.max_ul_slot_alloc_delay]); } +void uci_scheduler_impl::add_resource(rnti_t crnti, unsigned res_offset, unsigned res_period, bool is_sr) +{ + // For each offset in the periodic UCI slot wheel. + for (unsigned wheel_offset = res_offset; wheel_offset < periodic_uci_slot_wheel.size(); wheel_offset += res_period) { + auto& slot_wheel = periodic_uci_slot_wheel[wheel_offset]; + + // Check if the UE is already in the slot wheel. + auto it = std::find_if(slot_wheel.begin(), slot_wheel.end(), [crnti](const auto& r) { return r.rnti == crnti; }); + + if (it == slot_wheel.end()) { + // New UE. Create a new element in the list with either SR or CSI resource. + slot_wheel.push_back(periodic_uci_info{crnti, is_sr ? 1U : 0U, is_sr ? 0U : 1U}); + } else { + // Resource for UE already exists. Increment the resource counter. + if (is_sr) { + it->sr_counter++; + } else { + it->csi_counter++; + } + } + } +} + +void uci_scheduler_impl::rem_resource(rnti_t crnti, unsigned res_offset, unsigned res_period, bool is_sr) +{ + auto log_error = [&]() { + logger.error("cell={} c-rnti={}: Unable to remove {} PUCCH resource for period={} offset={}", + cell_cfg.cell_index, + crnti, + is_sr ? "SR" : "CSI", + res_period, + res_offset); + }; + + for (unsigned wheel_offset = res_offset; wheel_offset < periodic_uci_slot_wheel.size(); wheel_offset += res_period) { + auto& slot_wheel = periodic_uci_slot_wheel[wheel_offset]; + + auto it = std::find_if(slot_wheel.begin(), slot_wheel.end(), [crnti](const auto& r) { return r.rnti == crnti; }); + if (it != slot_wheel.end()) { + if (is_sr) { + if (it->sr_counter == 0) { + log_error(); + continue; + } + it->sr_counter--; + } else { + if (it->csi_counter == 0) { + log_error(); + continue; + } + it->csi_counter--; + } + + if (it->sr_counter == 0 and it->csi_counter == 0) { + // Move resource to last position and delete it to avoid O(N) removal. + if (it != slot_wheel.end() - 1) { + auto last_it = slot_wheel.end() - 1; + std::swap(it, last_it); + } + slot_wheel.pop_back(); + } + } else { + log_error(); + } + } +} + void uci_scheduler_impl::add_ue(const ue_cell_configuration& ue_cfg) { if (not ue_cfg.cfg_dedicated().ul_config.has_value() or @@ -54,9 +121,7 @@ void uci_scheduler_impl::add_ue(const ue_cell_configuration& ue_cfg) srsran_assert(sr_res.period >= sr_periodicity::sl_1, "Minimum supported SR periodicity is 1 slot."); unsigned period_slots = sr_periodicity_to_slot(sr_res.period); - for (unsigned offset = sr_res.offset; offset < periodic_uci_slot_wheel.size(); offset += period_slots) { - periodic_uci_slot_wheel[offset].push_back(periodic_uci_info{ue_cfg.crnti, true}); - } + add_resource(ue_cfg.crnti, sr_res.offset, period_slots, true); } if (ue_cfg.cfg_dedicated().csi_meas_cfg.has_value()) { @@ -67,10 +132,7 @@ void uci_scheduler_impl::add_ue(const ue_cell_configuration& ue_cfg) variant_get(csi_report_cfg.report_cfg_type); unsigned period_slots = csi_report_periodicity_to_uint(period_pucch.report_slot_period); - for (unsigned offset = period_pucch.report_slot_offset; offset < periodic_uci_slot_wheel.size(); - offset += period_slots) { - periodic_uci_slot_wheel[offset].push_back(periodic_uci_info{ue_cfg.crnti, false}); - } + add_resource(ue_cfg.crnti, period_pucch.report_slot_offset, period_slots, false); } // Register the UE in the list of recently configured UEs. @@ -110,13 +172,7 @@ void uci_scheduler_impl::rem_ue(const ue_cell_configuration& ue_cfg) const auto& sr_res = sr_resource_cfg_list[i]; unsigned period_slots = sr_periodicity_to_slot(sr_res.period); - for (unsigned offset = sr_res.offset; offset < periodic_uci_slot_wheel.size(); offset += period_slots) { - // Removing without keeping order as it is not relevant. - auto rem_it = std::remove_if(periodic_uci_slot_wheel[offset].begin(), - periodic_uci_slot_wheel[offset].end(), - [&ue_cfg](const auto& e) { return e.rnti == ue_cfg.crnti; }); - periodic_uci_slot_wheel[offset].erase(rem_it, periodic_uci_slot_wheel[offset].end()); - } + rem_resource(ue_cfg.crnti, sr_res.offset, period_slots, true); } if (ue_cfg.cfg_dedicated().csi_meas_cfg.has_value()) { @@ -127,13 +183,7 @@ void uci_scheduler_impl::rem_ue(const ue_cell_configuration& ue_cfg) variant_get(csi_report_cfg.report_cfg_type); unsigned period_slots = csi_report_periodicity_to_uint(period_pucch.report_slot_period); - for (unsigned offset = period_pucch.report_slot_offset; offset < periodic_uci_slot_wheel.size(); - offset += period_slots) { - auto rem_it = std::remove_if(periodic_uci_slot_wheel[offset].begin(), - periodic_uci_slot_wheel[offset].end(), - [&ue_cfg](const auto& e) { return e.rnti == ue_cfg.crnti; }); - periodic_uci_slot_wheel[offset].erase(rem_it, periodic_uci_slot_wheel[offset].end()); - } + rem_resource(ue_cfg.crnti, period_pucch.report_slot_offset, period_slots, false); } } @@ -152,33 +202,30 @@ const ue_cell_configuration* uci_scheduler_impl::get_ue_cfg(rnti_t rnti) const void uci_scheduler_impl::schedule_slot_ucis(cell_slot_resource_allocator& slot_alloc) { // For the provided slot, check if there are any pending UCI resources to allocate, and allocate them. - // NOTE: Allocating the CSI after the SR helps the PUCCH allocation to compute the number of allocated UCI bits and - // the corresponding number of PRBs for the PUCCH Format 2 over a PUCCH F2 grant is within PUCCH capacity. auto& slot_ucis = periodic_uci_slot_wheel[slot_alloc.slot.to_uint() % periodic_uci_slot_wheel.size()]; for (auto it = slot_ucis.begin(); it != slot_ucis.end();) { - const periodic_uci_info& uci_info = *it; - if (uci_info.is_sr) { - const ue_cell_configuration* ue_cfg = get_ue_cfg(uci_info.rnti); - if (ue_cfg != nullptr) { - uci_alloc.uci_allocate_sr_opportunity(slot_alloc, uci_info.rnti, *ue_cfg); - } else { - logger.error("UE with RNTI {} and cell={} not found.", uci_info.rnti, cell_cfg.cell_index); - it = slot_ucis.erase(it); - } + const periodic_uci_info& uci_info = *it; + const ue_cell_configuration* ue_cfg = get_ue_cfg(uci_info.rnti); + + if (ue_cfg == nullptr) { + logger.error( + "cell={} c-rnti={}: UE for which UCI is being scheduled was not found.", cell_cfg.cell_index, uci_info.rnti); + it = slot_ucis.erase(it); + continue; } - ++it; - } - for (auto it = slot_ucis.begin(); it != slot_ucis.end();) { - const periodic_uci_info& uci_info = *it; - if (not uci_info.is_sr) { - const ue_cell_configuration* ue_cfg = get_ue_cfg(uci_info.rnti); - if (ue_cfg != nullptr) { - uci_alloc.uci_allocate_csi_opportunity(slot_alloc, uci_info.rnti, *ue_cfg); - } else { - logger.error("UE with RNTI {} and cell={} not found.", uci_info.rnti, cell_cfg.cell_index); - it = slot_ucis.erase(it); - } + + // Schedule SR PUCCH first. + // NOTE: Allocating the CSI after the SR helps the PUCCH allocation to compute the number of allocated UCI bits and + // the corresponding number of PRBs for the PUCCH Format 2 over a PUCCH F2 grant is within PUCCH capacity. + if (uci_info.sr_counter > 0) { + uci_alloc.uci_allocate_sr_opportunity(slot_alloc, uci_info.rnti, *ue_cfg); + } + + // Schedule CSI PUCCH. + if (uci_info.csi_counter > 0) { + uci_alloc.uci_allocate_csi_opportunity(slot_alloc, uci_info.rnti, *ue_cfg); } + ++it; } } @@ -191,7 +238,7 @@ void uci_scheduler_impl::schedule_updated_ues_ucis(cell_resource_allocator& cell for (rnti_t rnti : updated_ues) { const ue_cell_configuration* ue_cfg = get_ue_cfg(rnti); if (ue_cfg == nullptr) { - logger.error("UE with RNTI {} and cell={} not found.", rnti, cell_cfg.cell_index); + logger.error("cell={} c-rnti={}: UE for which UCI is being scheduled was not found.", cell_cfg.cell_index, rnti); continue; } @@ -199,21 +246,18 @@ void uci_scheduler_impl::schedule_updated_ues_ucis(cell_resource_allocator& cell for (unsigned n = 0; n != cell_alloc.max_ul_slot_alloc_delay; ++n) { auto& slot_ucis = periodic_uci_slot_wheel[(cell_alloc.slot_tx() + n).to_uint() % periodic_uci_slot_wheel.size()]; - // Schedule SRs first - // NOTE: Allocating the CSI after the SR helps the PUCCH allocation to compute the number of allocated UCI bits - // and the corresponding number of PRBs for the PUCCH Format 2 over a PUCCH F2 grant is within PUCCH capacity. for (const periodic_uci_info& uci_info : slot_ucis) { if (uci_info.rnti == rnti) { - if (uci_info.is_sr) { + // Schedule SR PUCCHs first. + // NOTE: Allocating the CSI after the SR helps the PUCCH allocation to compute the number of allocated UCI + // bits and the corresponding number of PRBs for the PUCCH Format 2 over a PUCCH F2 grant is within PUCCH + // capacity. + if (uci_info.sr_counter > 0) { uci_alloc.uci_allocate_sr_opportunity(cell_alloc[n], rnti, *ue_cfg); } - } - } - // Schedule CSI - for (const periodic_uci_info& uci_info : slot_ucis) { - if (uci_info.rnti == rnti) { - if (not uci_info.is_sr) { + // Schedule CSI + if (uci_info.csi_counter > 0) { uci_alloc.uci_allocate_csi_opportunity(cell_alloc[n], rnti, *ue_cfg); } } diff --git a/lib/scheduler/uci_scheduling/uci_scheduler_impl.h b/lib/scheduler/uci_scheduling/uci_scheduler_impl.h index 7e563eda65..a49e9377c8 100644 --- a/lib/scheduler/uci_scheduling/uci_scheduler_impl.h +++ b/lib/scheduler/uci_scheduling/uci_scheduler_impl.h @@ -39,8 +39,9 @@ class uci_scheduler_impl final : public uci_scheduler private: /// Information on currently configured UE UCI resource to periodically schedule. struct periodic_uci_info { - rnti_t rnti; - bool is_sr; + rnti_t rnti = rnti_t::INVALID_RNTI; + unsigned sr_counter = 0; + unsigned csi_counter = 0; }; // Helper to fetch a UE cell config. @@ -50,6 +51,9 @@ class uci_scheduler_impl final : public uci_scheduler // Helper that schedules the SR and CSI for UEs that were recently updated. void schedule_updated_ues_ucis(cell_resource_allocator& res_alloc); + void add_resource(rnti_t crnti, unsigned offset, unsigned period, bool is_sr); + void rem_resource(rnti_t crnti, unsigned offset, unsigned period, bool is_sr); + // Cell configuration. const cell_configuration& cell_cfg; // Reference to PUCCH resource allocator object. @@ -58,7 +62,9 @@ class uci_scheduler_impl final : public uci_scheduler srslog::basic_logger& logger; - // Storage of the periodic UCIs to be scheduled in the resource grid. + // Storage of the periodic UCIs to be scheduled in the resource grid. Each position of the vector represents a slot + // in a ring-like structure (ie slot % WHEEL_SIZE). Each of these vector indexes/slots contains a list of periodic + // UCI information to be scheduled in the respective slot. std::vector> periodic_uci_slot_wheel; // UEs whose configuration has been updated in between the last and current slot indications. diff --git a/lib/scheduler/ue_scheduling/ue_event_manager.cpp b/lib/scheduler/ue_scheduling/ue_event_manager.cpp index 7f0acfd9e4..b0a658ecae 100644 --- a/lib/scheduler/ue_scheduling/ue_event_manager.cpp +++ b/lib/scheduler/ue_scheduling/ue_event_manager.cpp @@ -9,7 +9,6 @@ */ #include "ue_event_manager.h" -#include "../config/sched_config_manager.h" #include "../logging/scheduler_event_logger.h" #include "../logging/scheduler_metrics_handler.h" #include "../uci_scheduling/uci_scheduler_impl.h" @@ -183,7 +182,7 @@ void ue_event_manager::handle_ue_reconfiguration(ue_config_update_event ev) auto& new_ue_cc_cfg = ev.next_config().ue_cell_cfg(to_ue_cell_index(i)); auto* ue_cc = u.find_cell(new_ue_cc_cfg.cell_cfg_common.cell_index); if (ue_cc == nullptr) { - // new UE carrier is being added. + // New UE carrier is being added. du_cells[new_ue_cc_cfg.cell_cfg_common.cell_index].uci_sched->add_ue(new_ue_cc_cfg); } } From 1782e642311c0ba25a1ec6a755793d83232507a8 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Thu, 22 Feb 2024 14:16:17 +0100 Subject: [PATCH 030/140] sched: fix double removal of UE UCI resources from UCI scheduler --- lib/scheduler/ue_scheduling/ue_event_manager.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_event_manager.cpp b/lib/scheduler/ue_scheduling/ue_event_manager.cpp index b0a658ecae..b74eb0a5d0 100644 --- a/lib/scheduler/ue_scheduling/ue_event_manager.cpp +++ b/lib/scheduler/ue_scheduling/ue_event_manager.cpp @@ -190,12 +190,6 @@ void ue_event_manager::handle_ue_reconfiguration(ue_config_update_event ev) // Configure existing UE. ue_db[ue_idx].handle_reconfiguration_request(ue_reconf_command{ev.next_config()}); - // Update UCI scheduler with new resources. - for (unsigned i = 0; i != u.nof_cells(); ++i) { - auto& ue_cc = u.get_cell(to_ue_cell_index(i)); - du_cells[ue_cc.cell_index].uci_sched->rem_ue(ue_cc.cfg()); - } - // Log event. ev_logger.enqueue(scheduler_event_logger::ue_reconf_event{ue_idx, ue_db[ue_idx].crnti}); }); From df12b0437053b23095542de45974322f986a5306 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Thu, 22 Feb 2024 14:21:14 +0100 Subject: [PATCH 031/140] sched: add an log error if UCI scheduler UE resources are not correctly cleaned up --- lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp b/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp index 5fdbd39a35..347493a29b 100644 --- a/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp +++ b/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp @@ -28,7 +28,17 @@ uci_scheduler_impl::uci_scheduler_impl(const cell_configuration& cell_cfg_, updated_ues.reserve(MAX_NOF_DU_UES); } -uci_scheduler_impl::~uci_scheduler_impl() = default; +uci_scheduler_impl::~uci_scheduler_impl() +{ + for (auto& slot_entry : periodic_uci_slot_wheel) { + if (not slot_entry.empty()) { + logger.error("cell={} c-rnti={}: UCI resources were not correctly cleaned up from UCI scheduler", + cell_cfg.cell_index, + slot_entry[0].rnti); + break; + } + } +} void uci_scheduler_impl::run_slot(cell_resource_allocator& cell_alloc) { From b87423ddae143b25645b3581d8cb24873c22b6a9 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 27 Feb 2024 11:08:13 +0100 Subject: [PATCH 032/140] sched: remove check for configured uci pdus at scheduler destruction --- .../logging/scheduler_event_logger.cpp | 2 +- .../uci_scheduling/uci_scheduler_impl.cpp | 19 ++++++------------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/lib/scheduler/logging/scheduler_event_logger.cpp b/lib/scheduler/logging/scheduler_event_logger.cpp index 4d5d135bc6..7656e8cd83 100644 --- a/lib/scheduler/logging/scheduler_event_logger.cpp +++ b/lib/scheduler/logging/scheduler_event_logger.cpp @@ -169,7 +169,7 @@ void scheduler_event_logger::enqueue_impl(const bsr_event& bsr) fmtbuf, "{}{}: {}", i == 0 ? "" : " ", bsr.reported_lcgs[i].lcg_id, bsr.reported_lcgs[i].nof_bytes); } } - fmt::format_to(fmtbuf, "}} to_alloc={:B}", bsr.tot_ul_pending_bytes); + fmt::format_to(fmtbuf, "}} pending_bytes={}", bsr.tot_ul_pending_bytes); } } diff --git a/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp b/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp index 347493a29b..5e859a5867 100644 --- a/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp +++ b/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp @@ -28,17 +28,7 @@ uci_scheduler_impl::uci_scheduler_impl(const cell_configuration& cell_cfg_, updated_ues.reserve(MAX_NOF_DU_UES); } -uci_scheduler_impl::~uci_scheduler_impl() -{ - for (auto& slot_entry : periodic_uci_slot_wheel) { - if (not slot_entry.empty()) { - logger.error("cell={} c-rnti={}: UCI resources were not correctly cleaned up from UCI scheduler", - cell_cfg.cell_index, - slot_entry[0].rnti); - break; - } - } -} +uci_scheduler_impl::~uci_scheduler_impl() {} void uci_scheduler_impl::run_slot(cell_resource_allocator& cell_alloc) { @@ -218,8 +208,11 @@ void uci_scheduler_impl::schedule_slot_ucis(cell_slot_resource_allocator& slot_a const ue_cell_configuration* ue_cfg = get_ue_cfg(uci_info.rnti); if (ue_cfg == nullptr) { - logger.error( - "cell={} c-rnti={}: UE for which UCI is being scheduled was not found.", cell_cfg.cell_index, uci_info.rnti); + logger.error("cell={} c-rnti={}: UE for which {} is being scheduled was not found (slot={})", + cell_cfg.cell_index, + uci_info.rnti, + it->sr_counter > 0 ? "SR" : (it->csi_counter > 0 ? "CSI" : "invalid UCI"), + slot_alloc.slot); it = slot_ucis.erase(it); continue; } From 37214106256905c20c87f458b5468cd186c97586 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 27 Feb 2024 12:11:40 +0100 Subject: [PATCH 033/140] sched: fix removal of UE in UCI scheduler. --- lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp b/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp index 5e859a5867..9373155991 100644 --- a/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp +++ b/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp @@ -97,7 +97,7 @@ void uci_scheduler_impl::rem_resource(rnti_t crnti, unsigned res_offset, unsigne // Move resource to last position and delete it to avoid O(N) removal. if (it != slot_wheel.end() - 1) { auto last_it = slot_wheel.end() - 1; - std::swap(it, last_it); + std::swap(*it, *last_it); } slot_wheel.pop_back(); } From 384c0ecc50ddf9f7a6e29ce3ccad058abc3837f5 Mon Sep 17 00:00:00 2001 From: asaezper Date: Tue, 27 Feb 2024 12:24:30 +0100 Subject: [PATCH 034/140] ci: update retina to add ps info --- .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 30b3b5f79e..2a8eadab19 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.43.0 +RETINA_VERSION=0.43.1 AMARISOFT_VERSION=2023-03-17 SRSUE_VERSION=23.11 OPEN5GS_VERSION=2.6.1 From 954649ea8b2ef213a1f26149709c41ffbd275c0f Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Mon, 19 Feb 2024 17:12:39 +0000 Subject: [PATCH 035/140] cu_cp: reduce default inactivity timer --- apps/gnb/gnb_appconfig.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/gnb/gnb_appconfig.h b/apps/gnb/gnb_appconfig.h index 023fd844f9..4725ca18e8 100644 --- a/apps/gnb/gnb_appconfig.h +++ b/apps/gnb/gnb_appconfig.h @@ -719,8 +719,8 @@ struct security_appconfig { struct cu_cp_appconfig { uint16_t max_nof_dus = 6; uint16_t max_nof_cu_ups = 6; - int inactivity_timer = 7200; // in seconds - unsigned ue_context_setup_timeout_s = 3; // in seconds (must be larger than T310) + int inactivity_timer = 5; // in seconds + unsigned ue_context_setup_timeout_s = 3; // in seconds (must be larger than T310) mobility_appconfig mobility_config; rrc_appconfig rrc_config; security_appconfig security_config; From 0a0889f47fc7109b9975a1dd9b22c8ed6efe9b42 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Fri, 23 Feb 2024 18:19:52 +0100 Subject: [PATCH 036/140] rlc_rx_am: refactor reassembly of SDUs - perform SDU reassembly in a function - evaluate successful creation of byte_buffer_chain --- lib/rlc/rlc_rx_am_entity.cpp | 117 +++++++++++++++++++++++------------ lib/rlc/rlc_rx_am_entity.h | 49 ++++++++++----- 2 files changed, 111 insertions(+), 55 deletions(-) diff --git a/lib/rlc/rlc_rx_am_entity.cpp b/lib/rlc/rlc_rx_am_entity.cpp index 7649fec2e7..a2e13c8c0b 100644 --- a/lib/rlc/rlc_rx_am_entity.cpp +++ b/lib/rlc/rlc_rx_am_entity.cpp @@ -199,16 +199,20 @@ void rlc_rx_am_entity::handle_data_pdu(byte_buffer_slice buf) * - reassemble the RLC SDU from AMD PDU(s) with SN = x, remove RLC headers when doing so and deliver * the reassembled RLC SDU to upper layer; */ - rlc_rx_am_sdu_info& rx_sdu = (*rx_window)[header.sn]; - if (rx_sdu.sdu.empty()) { - logger.log_error("RX SDU failed: SDU is empty. sn={}", header.sn); + rlc_rx_am_sdu_info& sdu_info = (*rx_window)[header.sn]; + expected sdu = reassemble_sdu(sdu_info, header.sn); + if (!sdu) { + logger.log_error("Dropped SDU, failed to reassemble. sn={}", header.sn); metrics.metrics_add_lost_pdus(1); // Do not pass empty SDU to upper layers and continue as normal to maintain state } else { - logger.log_info("RX SDU. sn={} sdu_len={}", header.sn, rx_sdu.sdu.length()); - metrics.metrics_add_sdus(1, rx_sdu.sdu.length()); - upper_dn.on_new_sdu(std::move(rx_sdu.sdu)); + logger.log_info("RX SDU. sn={} sdu_len={}", header.sn, sdu.value().length()); + metrics.metrics_add_sdus(1, sdu.value().length()); + upper_dn.on_new_sdu(std::move(sdu.value())); } + // Release all buffers of sdu_data; keep "fully_received == true" for correct construction of status report + sdu_info.sdu_data = {}; + /* * - if x = RX_Highest_Status, * - update RX_Highest_Status to the SN of the first RLC SDU with SN > current RX_Highest_Status for which not @@ -326,9 +330,8 @@ bool rlc_rx_am_entity::handle_full_data_sdu(const rlc_am_pdu_header& header, byt // Add new SN to RX window if no segments have been received yet rlc_rx_am_sdu_info& rx_sdu = rx_window->has_sn(header.sn) ? (*rx_window)[header.sn] : rx_window->add_sn(header.sn); - // Full SDU received. Clear segments and use full payload as SDU. - rx_sdu.segments.clear(); - rx_sdu.sdu = std::move(payload); + // Store the full SDU and flag it as complete. + rx_sdu.sdu_data = std::move(payload); rx_sdu.fully_received = true; rx_sdu.has_gap = false; return true; @@ -358,26 +361,6 @@ bool rlc_rx_am_entity::handle_segment_data_sdu(const rlc_am_pdu_header& header, // Check whether all segments have been received update_segment_inventory(rx_sdu); - logger.log_debug("Updated segment inventory. sn={} {}", header.sn, rx_sdu); - if (rx_sdu.fully_received) { - // Assemble SDU from segments - for (const rlc_rx_am_sdu_segment& segm : rx_sdu.segments) { - logger.log_debug("Chaining segment. sn={} so={} len={}", header.sn, segm.so, segm.payload.length()); - if (not rx_sdu.sdu.append(segm.payload.copy())) { - logger.log_error("Unable to append segment in byte_buffer_chain. sn={} {}", header.sn, rx_sdu); - // Clear the incomplete SDU to be discarded later before passing it to upper layers. - rx_sdu.sdu.clear(); - break; - } - } - if (not rx_sdu.sdu.empty()) { - logger.log_debug("Assembled SDU from segments. sn={} sdu_len={}", header.sn, rx_sdu.sdu.length()); - } else { - logger.log_error("Failed to assemble SDU from segments. sn={} {}", header.sn, rx_sdu); - } - // Release segments - rx_sdu.segments.clear(); - } return stored; } @@ -385,8 +368,13 @@ bool rlc_rx_am_entity::store_segment(rlc_rx_am_sdu_info& sdu_info, rlc_rx_am_sdu { // Section 5.2.3.2.2, discard segments with overlapping bytes - std::set::iterator cur_segment = sdu_info.segments.begin(); - while (cur_segment != sdu_info.segments.end()) { + if (!variant_holds_alternative(sdu_info.sdu_data)) { + // put an empty set + sdu_info.sdu_data = rlc_rx_am_sdu_info::segment_set_t{}; + } + rlc_rx_am_sdu_info::segment_set_t& segments = variant_get(sdu_info.sdu_data); + auto cur_segment = segments.begin(); + while (cur_segment != segments.end()) { uint32_t cur_last_byte = cur_segment->so + cur_segment->payload.length() - 1; uint32_t new_last_byte = new_segment.so + new_segment.payload.length() - 1; if (new_segment.so > cur_last_byte) { @@ -441,9 +429,9 @@ bool rlc_rx_am_entity::store_segment(rlc_rx_am_sdu_info& sdu_info, rlc_rx_am_sdu rlc_rx_am_sdu_segment cut_segment{*cur_segment}; cut_segment.payload.advance(new_last_byte + 1 - cur_segment->so); cut_segment.so = new_last_byte + 1; - sdu_info.segments.erase(cur_segment++); + segments.erase(cur_segment++); // insert cut segment as close as possible before (next) current segment - this is faster than plain insert - sdu_info.segments.insert(cur_segment, std::move(cut_segment)); + segments.insert(cur_segment, std::move(cut_segment)); // exit loop and insert new segment afterwards break; } @@ -451,16 +439,19 @@ bool rlc_rx_am_entity::store_segment(rlc_rx_am_sdu_info& sdu_info, rlc_rx_am_sdu // cur: bcde // new: ...abcdef... // remove current segment, check next segment - sdu_info.segments.erase(cur_segment++); + segments.erase(cur_segment++); } // insert new segment as close as possible before current segment - this is faster than plain insert - sdu_info.segments.insert(cur_segment, std::move(new_segment)); + segments.insert(cur_segment, std::move(new_segment)); return true; } void rlc_rx_am_entity::update_segment_inventory(rlc_rx_am_sdu_info& rx_sdu) const { - if (rx_sdu.segments.empty()) { + srsran_assert(variant_holds_alternative(rx_sdu.sdu_data), + "Invalid sdu_data variant for update of segment inventory"); + rlc_rx_am_sdu_info::segment_set_t& segments = variant_get(rx_sdu.sdu_data); + if (segments.empty()) { rx_sdu.fully_received = false; rx_sdu.has_gap = false; return; @@ -468,7 +459,7 @@ void rlc_rx_am_entity::update_segment_inventory(rlc_rx_am_sdu_info& rx_sdu) cons // Check for gaps and if all segments have been received uint32_t next_byte = 0; - for (const rlc_rx_am_sdu_segment& segm : rx_sdu.segments) { + for (const rlc_rx_am_sdu_segment& segm : segments) { if (segm.so != next_byte) { // Found gap: set flags and return rx_sdu.has_gap = true; @@ -488,6 +479,48 @@ void rlc_rx_am_entity::update_segment_inventory(rlc_rx_am_sdu_info& rx_sdu) cons rx_sdu.fully_received = false; } +expected rlc_rx_am_entity::reassemble_sdu(rlc_rx_am_sdu_info& sdu_info, uint32_t sn) +{ + // Sanity check + if (!sdu_info.fully_received) { + logger.log_error("Cannot reassemble SDU not marked as fully_received. sn={} {}", sn, sdu_info); + return {default_error_t{}}; + } + + expected sdu = byte_buffer_chain(); // TODO USE byte_buffer_chain::create() + if (!sdu) { + logger.log_error("Failed to create SDU buffer. sn={} {}", sn, sdu_info); + return {default_error_t{}}; + } + + if (variant_holds_alternative(sdu_info.sdu_data)) { + // Handling for full SDU + byte_buffer_slice& payload = variant_get(sdu_info.sdu_data); + if (!sdu.value().append(std::move(payload))) { + logger.log_error("Failed to append segment in SDU buffer. sn={} {}", sn, sdu_info); + return {default_error_t{}}; + } + } else if (variant_holds_alternative(sdu_info.sdu_data)) { + rlc_rx_am_sdu_info::segment_set_t& segments = variant_get(sdu_info.sdu_data); + for (const rlc_rx_am_sdu_segment& segm : segments) { + logger.log_debug("Chaining segment. sn={} so={} len={}", sn, segm.so, segm.payload.length()); + if (!sdu.value().append(segm.payload.copy())) { + logger.log_error("Failed to append segment in SDU buffer. sn={} so={} len={} {}", + sn, + segm.so, + segm.payload.length(), + sdu_info); + return {default_error_t{}}; + } + } + logger.log_debug("Assembled SDU from segments. sn={} sdu_len={}", sn, sdu.value().length()); + } else { + logger.log_error("Unhandled variant of sdu_data. sn={} {}", sn, sdu_info); + } + + return sdu; +} + void rlc_rx_am_entity::refresh_status_report() { status_builder->reset(); @@ -516,11 +549,16 @@ void rlc_rx_am_entity::refresh_status_report() logger.log_debug("Adding nack={}.", nack); status_builder->push_nack(nack); } else if (not(*rx_window)[i].fully_received) { + srsran_assert(variant_holds_alternative((*rx_window)[i].sdu_data), + "Invalid sdu_data variant of incomplete SDU in rx_window. sn={}", + i); + rlc_rx_am_sdu_info::segment_set_t& segments = + variant_get((*rx_window)[i].sdu_data); // Some segments were received, but not all. // NACK non consecutive missing bytes uint32_t last_so = 0; bool have_last_segment = false; - for (auto segm = (*rx_window)[i].segments.begin(); segm != (*rx_window)[i].segments.end(); segm++) { + for (auto segm = segments.begin(); segm != segments.end(); segm++) { if (segm->so != last_so) { // Some bytes were not received rlc_am_status_nack nack; @@ -534,8 +572,7 @@ void rlc_rx_am_entity::refresh_status_report() // Sanity check if (nack.so_start > nack.so_end) { // Print segment list - for (auto segm_it = (*rx_window)[i].segments.begin(); segm_it != (*rx_window)[i].segments.end(); - segm_it++) { + for (auto segm_it = segments.begin(); segm_it != segments.end(); segm_it++) { logger.log_error("Segment: so={} len={}", segm_it->so, segm_it->payload.length()); } logger.log_error("Invalid segment offsets in nack={} for segment so={}.", nack, segm->so); diff --git a/lib/rlc/rlc_rx_am_entity.h b/lib/rlc/rlc_rx_am_entity.h index 9eb06339e7..97a0c287dc 100644 --- a/lib/rlc/rlc_rx_am_entity.h +++ b/lib/rlc/rlc_rx_am_entity.h @@ -13,6 +13,7 @@ #include "rlc_am_interconnect.h" #include "rlc_am_pdu.h" #include "rlc_rx_entity.h" +#include "srsran/adt/expected.h" #include "srsran/support/executors/task_executor.h" #include "srsran/support/sdu_window.h" #include "srsran/support/timers.h" @@ -33,16 +34,16 @@ struct rlc_rx_am_sdu_segment_cmp { bool operator()(const rlc_rx_am_sdu_segment& a, const rlc_rx_am_sdu_segment& b) const { return a.so < b.so; } }; -/// Container to collect received SDU segments and to assemble the SDU upon completion +/// Container for buffering of received SDUs or SDU segments until fully received. struct rlc_rx_am_sdu_info { - // TODO: Refactor this struct. - // Move the following rlc_rx_am methods here: - // - add segments without duplicates - // - assemble SDU - bool fully_received = false; - bool has_gap = false; - std::set segments; // Set of segments with SO as key - byte_buffer_chain sdu = {}; + using segment_set_t = std::set; // Set of segments with SO as key + + /// Flags the SDU as fully received or not. + bool fully_received = false; + /// Indicates a gap (i.e. a missing segment) among all already received segments. + bool has_gap = false; + /// Buffer for either a full SDU or a set of SDU segments. + variant sdu_data; }; /// \brief Rx state variables @@ -271,6 +272,13 @@ class rlc_rx_am_entity : public rlc_rx_entity, public rlc_rx_am_status_provider /// \param rx_sdu Container/Info object to be inspected void update_segment_inventory(rlc_rx_am_sdu_info& rx_sdu) const; + /// Reassembles a fully received SDU from buffered segment(s) in the SDU info object. + /// + /// \param sdu_info The SDU info to be reassembled. + /// \param sn Sequence number (for logging). + /// \return The reassembled SDU in case of success, default_error_t{} otherwise. + expected reassemble_sdu(rlc_rx_am_sdu_info& sdu_info, uint32_t sn); + /// Rebuilds the cached status_report according to missing SDUs and SDU segments in rx_window /// and resets the rx_window_changed flag void refresh_status_report(); @@ -312,12 +320,23 @@ struct formatter { auto format(const srsran::rlc_rx_am_sdu_info& info, FormatContext& ctx) -> decltype(std::declval().out()) { - return format_to(ctx.out(), - "nof_segments={} has_gap={} fully_received={} sdu_len={}", - info.segments.size(), - info.has_gap, - info.fully_received, - info.sdu.length()); + if (srsran::variant_holds_alternative(info.sdu_data)) { + // full SDU + const srsran::byte_buffer_slice& payload = srsran::variant_get(info.sdu_data); + return format_to( + ctx.out(), "has_gap={} fully_received={} sdu_len={}", info.has_gap, info.fully_received, payload.length()); + } else if (srsran::variant_holds_alternative(info.sdu_data)) { + // segmented SDU + const srsran::rlc_rx_am_sdu_info::segment_set_t& segments = + srsran::variant_get(info.sdu_data); + return format_to(ctx.out(), + "has_gap={} fully_received={} nof_segments={}", + info.has_gap, + info.fully_received, + segments.size()); + } + // unset default case - neither full SDU nor segmented SDU + return format_to(ctx.out(), "has_gap={} fully_received={}", info.has_gap, info.fully_received); } }; From 3e1275ca03b949ea5c8774bc0be2241eb8381e70 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Tue, 27 Feb 2024 12:54:08 +0100 Subject: [PATCH 037/140] rlc_rx_um: refactor reassembly of SDUs - perform SDU reassembly in a function - evaluate successful creation of byte_buffer_chain --- lib/rlc/rlc_rx_um_entity.cpp | 67 +++++++++++++++++++++--------------- lib/rlc/rlc_rx_um_entity.h | 31 ++++++++++------- 2 files changed, 59 insertions(+), 39 deletions(-) diff --git a/lib/rlc/rlc_rx_um_entity.cpp b/lib/rlc/rlc_rx_um_entity.cpp index 80755aeed1..b88aa1ffd5 100644 --- a/lib/rlc/rlc_rx_um_entity.cpp +++ b/lib/rlc/rlc_rx_um_entity.cpp @@ -98,16 +98,19 @@ void rlc_rx_um_entity::handle_pdu(byte_buffer_slice buf) * - reassemble the RLC SDU from all byte segments with SN = x, remove RLC headers and deliver the reassembled * RLC SDU to upper layer; */ - rlc_rx_um_sdu_info& rx_sdu = (*rx_window)[header.sn]; - if (rx_sdu.sdu.empty()) { - logger.log_error("RX SDU failed: SDU is empty. sn={}", header.sn); + rlc_rx_um_sdu_info& sdu_info = (*rx_window)[header.sn]; + expected sdu = reassemble_sdu(sdu_info, header.sn); + if (!sdu) { + logger.log_error("Dropped SDU, failed to reassemble. sn={}", header.sn); metrics.metrics_add_lost_pdus(1); // Do not pass empty SDU to upper layers and continue as normal to maintain state } else { - logger.log_info("RX SDU. sn={} sdu_len={}", header.sn, rx_sdu.sdu.length()); - metrics.metrics_add_sdus(1, rx_sdu.sdu.length()); - upper_dn.on_new_sdu(std::move(rx_sdu.sdu)); + logger.log_info("RX SDU. sn={} sdu_len={}", header.sn, sdu.value().length()); + metrics.metrics_add_sdus(1, sdu.value().length()); + upper_dn.on_new_sdu(std::move(sdu.value())); } + // Release all segments + sdu_info.segments.clear(); /* * - if x = RX_Next_Reassembly: @@ -275,26 +278,6 @@ bool rlc_rx_um_entity::handle_segment_data_sdu(const rlc_um_pdu_header& header, // Check whether all segments have been received update_segment_inventory(rx_sdu); - logger.log_debug("Updated segment inventory. sn={} {}", header.sn, rx_sdu); - if (rx_sdu.fully_received) { - // Assemble SDU from segments - for (const rlc_rx_um_sdu_segment& segm : rx_sdu.segments) { - logger.log_debug("Chaining segment. sn={} so={} len={}", header.sn, segm.so, segm.payload.length()); - if (not rx_sdu.sdu.append(segm.payload.copy())) { - logger.log_error("Unable to append segment in byte_buffer_chain. sn={} {}", header.sn, rx_sdu); - // Clear the incomplete SDU to be discarded later before passing it to upper layers. - rx_sdu.sdu.clear(); - break; - } - } - if (not rx_sdu.sdu.empty()) { - logger.log_debug("Assembled SDU from segments. sn={} sdu_len={}", header.sn, rx_sdu.sdu.length()); - } else { - logger.log_error("Failed to assemble SDU from segments. sn={} {}", header.sn, rx_sdu); - } - // Release segments - rx_sdu.segments.clear(); - } return stored; } @@ -303,7 +286,7 @@ bool rlc_rx_um_entity::store_segment(rlc_rx_um_sdu_info& sdu_info, rlc_rx_um_sdu // Section 5.2.2.2.2; Although not supposed to happen in UM, we check and discard segments with overlapping bytes // as described in Section 5.2.3.2.2 for AM. - std::set::iterator cur_segment = sdu_info.segments.begin(); + auto cur_segment = sdu_info.segments.begin(); while (cur_segment != sdu_info.segments.end()) { uint32_t cur_last_byte = cur_segment->so + cur_segment->payload.length() - 1; uint32_t new_last_byte = new_segment.so + new_segment.payload.length() - 1; @@ -406,6 +389,36 @@ void rlc_rx_um_entity::update_segment_inventory(rlc_rx_um_sdu_info& rx_sdu) cons rx_sdu.fully_received = false; } +expected rlc_rx_um_entity::reassemble_sdu(rlc_rx_um_sdu_info& sdu_info, uint32_t sn) +{ + // Sanity check + if (!sdu_info.fully_received) { + logger.log_error("Cannot reassemble SDU not marked as fully_received. sn={} {}", sn, sdu_info); + return {default_error_t{}}; + } + + expected sdu = byte_buffer_chain(); // TODO USE byte_buffer_chain::create() + if (!sdu) { + logger.log_error("Failed to create SDU buffer. sn={} {}", sn, sdu_info); + return {default_error_t{}}; + } + + for (const rlc_rx_um_sdu_segment& segm : sdu_info.segments) { + logger.log_debug("Chaining segment. sn={} so={} len={}", sn, segm.so, segm.payload.length()); + if (!sdu.value().append(segm.payload.copy())) { + logger.log_error("Failed to append segment in SDU buffer. sn={} so={} len={} {}", + sn, + segm.so, + segm.payload.length(), + sdu_info); + return {default_error_t{}}; + } + } + logger.log_debug("Assembled SDU from segments. sn={} sdu_len={}", sn, sdu.value().length()); + + return sdu; +} + // TS 38.322 v16.2.0 Sec. 5.2.2.2.4 void rlc_rx_um_entity::on_expired_reassembly_timer() { diff --git a/lib/rlc/rlc_rx_um_entity.h b/lib/rlc/rlc_rx_um_entity.h index 9dd000c0a4..b3965feb7f 100644 --- a/lib/rlc/rlc_rx_um_entity.h +++ b/lib/rlc/rlc_rx_um_entity.h @@ -12,6 +12,7 @@ #include "rlc_rx_entity.h" #include "rlc_um_pdu.h" +#include "srsran/adt/expected.h" #include "srsran/support/executors/task_executor.h" #include "srsran/support/sdu_window.h" #include "srsran/support/timers.h" @@ -32,16 +33,16 @@ struct rlc_rx_um_sdu_segment_cmp { bool operator()(const rlc_rx_um_sdu_segment& a, const rlc_rx_um_sdu_segment& b) const { return a.so < b.so; } }; -/// Container to collect received SDU segments and to assemble the SDU upon completion +/// Container for buffering of received SDU segments until fully received. struct rlc_rx_um_sdu_info { - // TODO: Refactor this struct. - // Move the following rlc_rx_um methods here: - // - add segments without duplicates - // - assemble SDU - bool fully_received = false; - bool has_gap = false; - std::set segments; // Set of segments with SO as key - byte_buffer_chain sdu = {}; + using segment_set_t = std::set; // Set of segments with SO as key + + /// Flags the SDU as fully received or not. + bool fully_received = false; + /// Indicates a gap (i.e. a missing segment) among all already received segments. + bool has_gap = false; + /// Buffer for set of SDU segments. + segment_set_t segments; }; /// \brief Rx state variables @@ -132,6 +133,13 @@ class rlc_rx_um_entity : public rlc_rx_entity /// \param rx_sdu Container/Info object to be inspected void update_segment_inventory(rlc_rx_um_sdu_info& rx_sdu) const; + /// Reassembles a fully received SDU from buffered segments in the SDU info object. + /// + /// \param sdu_info The SDU info to be reassembled. + /// \param sn Sequence number (for logging). + /// \return The reassembled SDU in case of success, default_error_t{} otherwise. + expected reassemble_sdu(rlc_rx_um_sdu_info& sdu_info, uint32_t sn); + /// Creates the rx_window according to sn_size /// \param sn_size Size of the sequence number (SN) /// \return unique pointer to rx_window instance @@ -166,11 +174,10 @@ struct formatter { -> decltype(std::declval().out()) { return format_to(ctx.out(), - "nof_segments={} has_gap={} fully_received={} sdu_len={}", - info.segments.size(), + "has_gap={} fully_received={} nof_segments={}", info.has_gap, info.fully_received, - info.sdu.length()); + info.segments.size()); } }; From aa2dbfe468a0d100354de4621bfc54a9e78b6917 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Mon, 26 Feb 2024 18:10:10 +0100 Subject: [PATCH 038/140] sched: discount PUCCH grants from max UL grants Signed-off-by: Carlo Galiotto --- .../ue_scheduling/ue_cell_grid_allocator.cpp | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp index 3e9c18344c..a622c590c4 100644 --- a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp @@ -534,12 +534,6 @@ alloc_outcome ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& gr expert_cfg.max_puschs_per_slot); return alloc_outcome::skip_slot; } - if (pusch_alloc.result.ul.puschs.size() >= - expert_cfg.max_ul_grants_per_slot - static_cast(pusch_alloc.result.ul.pucchs.size())) { - logger.info("Failed to allocate PUSCH. Cause: Max number of UL grants per slot {} was reached.", - expert_cfg.max_puschs_per_slot); - return alloc_outcome::skip_slot; - } // Verify there is space in PUSCH and PDCCH result lists for new allocations. if (pusch_alloc.result.ul.puschs.full() or pdcch_alloc.result.dl.ul_pdcchs.full()) { @@ -556,16 +550,17 @@ alloc_outcome ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& gr } } + const unsigned nof_pucch_grants = + std::count_if(pusch_alloc.result.ul.pucchs.begin(), + pusch_alloc.result.ul.pucchs.end(), + [&u](const pucch_info& pucch_grant) { return pucch_grant.crnti == u.crnti; }); + // [Implementation-defined] We skip allocation of PUSCH if there is already a PUCCH grant scheduled over the same slot // and the UE is in fallback mode. // NOTE: This is due to the lack of clarity of the TS when it comes to define what \c betaOffsets to use for PUSCH // when the UE does not have a dedicated configuration. if (ue_cc->is_in_fallback_mode()) { - const auto* pucch_grant_it = - std::find_if(pusch_alloc.result.ul.pucchs.begin(), - pusch_alloc.result.ul.pucchs.end(), - [&u](const pucch_info& pucch_grant) { return pucch_grant.crnti == u.crnti; }); - if (pucch_grant_it != pusch_alloc.result.ul.pucchs.end()) { + if (nof_pucch_grants != 0) { logger.debug("rnti={} Allocation of PUSCH in slot={} skipped. Cause: this UE is in fallback mode and has " "PUCCH grants scheduled", u.crnti, @@ -574,6 +569,16 @@ alloc_outcome ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& gr } } + // When checking the number of remaining grants for PUSCH, take into account that the PUCCH grants for this UE will be + // removed when multiplexing the UCI on PUSCH. + if (pusch_alloc.result.ul.puschs.size() >= + expert_cfg.max_ul_grants_per_slot - + (static_cast(pusch_alloc.result.ul.pucchs.size()) - nof_pucch_grants)) { + logger.info("Failed to allocate PUSCH. Cause: Max number of UL grants per slot {} was reached.", + expert_cfg.max_puschs_per_slot); + return alloc_outcome::skip_slot; + } + // Verify CRBs allocation. if (not ss_info->ul_crb_lims.contains(grant.crbs)) { logger.warning("rnti={} Failed to allocate PUSCH. Cause: CRBs {} allocated outside the BWP {}", From 50e5f59b80d915ab250d46dff74569d512692172 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Mon, 26 Feb 2024 14:35:24 +0100 Subject: [PATCH 039/140] rlc_rx_am_benchmark: configurable size of SDUs and PDUs --- tests/benchmarks/rlc/rlc_am_rx_benchmark.cpp | 29 +++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/tests/benchmarks/rlc/rlc_am_rx_benchmark.cpp b/tests/benchmarks/rlc/rlc_am_rx_benchmark.cpp index ffcfafa09c..5aefad30db 100644 --- a/tests/benchmarks/rlc/rlc_am_rx_benchmark.cpp +++ b/tests/benchmarks/rlc/rlc_am_rx_benchmark.cpp @@ -69,6 +69,8 @@ class rlc_rx_am_test_frame : public rlc_rx_upper_layer_data_notifier, struct bench_params { unsigned nof_repetitions = 10000; + unsigned sdu_size = 1500; + unsigned pdu_size = 1550; }; enum class rx_order { @@ -82,17 +84,25 @@ static void usage(const char* prog, const bench_params& params) { fmt::print("Usage: {} [-R repetitions] [-s silent]\n", prog); fmt::print("\t-R Repetitions [Default {}]\n", params.nof_repetitions); + fmt::print("\t-s SDU size [Default {}]\n", params.sdu_size); + fmt::print("\t-p PDU size [Default {}]\n", params.pdu_size); fmt::print("\t-h Show this message\n"); } static void parse_args(int argc, char** argv, bench_params& params) { int opt = 0; - while ((opt = getopt(argc, argv, "R:h")) != -1) { + while ((opt = getopt(argc, argv, "R:s:p:h")) != -1) { switch (opt) { case 'R': params.nof_repetitions = std::strtol(optarg, nullptr, 10); break; + case 's': + params.sdu_size = std::strtol(optarg, nullptr, 10); + break; + case 'p': + params.pdu_size = std::strtol(optarg, nullptr, 10); + break; case 'h': default: usage(argv[0], params); @@ -148,7 +158,7 @@ std::vector generate_pdus(bench_params params, rx_order order) // Prepare SDU list for benchmark std::vector sdu_list = {}; int num_sdus = params.nof_repetitions + 1; // +1 to expire t_reassembly on setup - int num_bytes = 1500; + int num_bytes = params.sdu_size; for (int i = 0; i < num_sdus; i++) { byte_buffer sdu_buf = {}; for (int j = 0; j < num_bytes; ++j) { @@ -157,6 +167,8 @@ std::vector generate_pdus(bench_params params, rx_order order) sdu_list.push_back(std::move(sdu_buf)); } + int num_pdus = 0; + int pdu_size = params.pdu_size; for (int i = 0; i < num_sdus; i++) { rlc_sdu sdu; byte_buffer pdcp_hdr_buf = {0x80, 0x00, 0x16}; @@ -165,11 +177,14 @@ std::vector generate_pdus(bench_params params, rx_order order) sdu.buf = std::move(pdcp_hdr_buf); report_error_if_not(sdu.buf.append(std::move(sdu_buf)), "Failed to allocate SDU"); rlc_tx->handle_sdu(std::move(sdu)); - std::vector pdu_buf; - pdu_buf.resize(1550); - size_t pdu_len = rlc_tx->pull_pdu(pdu_buf); - pdu_buf.resize(pdu_len); - pdus.push_back(byte_buffer{pdu_buf}); + while (rlc_tx->get_buffer_state() > 0) { + std::vector pdu_buf; + pdu_buf.resize(pdu_size); + size_t pdu_len = rlc_tx->pull_pdu(pdu_buf); + pdu_buf.resize(pdu_len); + pdus.emplace_back(pdu_buf); + num_pdus++; + } } // shuffle PDUs according to requested order From 57711b6c16f5e1c23967c1ee029f406145293704 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Mon, 26 Feb 2024 14:35:52 +0100 Subject: [PATCH 040/140] rlc_rx_am_benchmark: fix even_odd testcase --- tests/benchmarks/rlc/rlc_am_rx_benchmark.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/benchmarks/rlc/rlc_am_rx_benchmark.cpp b/tests/benchmarks/rlc/rlc_am_rx_benchmark.cpp index 5aefad30db..9da95a4b49 100644 --- a/tests/benchmarks/rlc/rlc_am_rx_benchmark.cpp +++ b/tests/benchmarks/rlc/rlc_am_rx_benchmark.cpp @@ -198,14 +198,14 @@ std::vector generate_pdus(bench_params params, rx_order order) std::reverse(pdus.begin(), pdus.end()); break; case rx_order::even_odd: - std::vector sdu_list_mod; - for (int i = 0; i < num_sdus; i += 2) { - sdu_list_mod.push_back(std::move(sdu_list[i])); + std::vector pdus_mod; + for (int i = 0; i < num_pdus; i += 2) { + pdus_mod.push_back(std::move(pdus[i])); } - for (int i = 1; i < num_sdus; i += 2) { - sdu_list_mod.push_back(std::move(sdu_list[i])); + for (int i = 1; i < num_pdus; i += 2) { + pdus_mod.push_back(std::move(pdus[i])); } - sdu_list = std::move(sdu_list_mod); + pdus = std::move(pdus_mod); break; } From 27efc6556a28510036e9d94d4750d94f01b3888f Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Tue, 27 Feb 2024 12:01:55 +0100 Subject: [PATCH 041/140] epoll: reorder registration of file descriptor and handler This change ensures that the event handler is in place at the time of registration at epoll. If the registration fails, the event handler will be removed. --- lib/support/network/io_broker_epoll.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/support/network/io_broker_epoll.cpp b/lib/support/network/io_broker_epoll.cpp index ba2194875c..8ae3f04982 100644 --- a/lib/support/network/io_broker_epoll.cpp +++ b/lib/support/network/io_broker_epoll.cpp @@ -126,18 +126,25 @@ void io_broker_epoll::thread_loop() /// file descriptors can be added while the epoll_wait() is blocking. bool io_broker_epoll::register_fd(int fd, recv_callback_t handler) { + logger.debug("Registering file descriptor. fd={}", fd); + + { + // add event handler to map before registering it at epoll control + std::lock_guard lock(event_handler_mutex); + event_handler.insert({fd, std::make_unique(handler)}); + } + struct epoll_event ev = {}; ev.data.fd = fd; ev.events = EPOLLIN; if (::epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) { logger.error("Failed to register file descriptor. fd={} error={}", fd, strerror(errno)); + // remove event handler from map + std::lock_guard lock(event_handler_mutex); + event_handler.erase(fd); return false; } - std::lock_guard lock(event_handler_mutex); - event_handler.insert({fd, std::make_unique(handler)}); - - logger.debug("Registered file descriptor. fd={}", fd); return true; } From dfacb7ae7a6721532660539ff11f83e32cb95646 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Mon, 26 Feb 2024 13:33:08 +0000 Subject: [PATCH 042/140] pdcp: add log filename and log level configuration to TX PDCP benchmark --- tests/benchmarks/pdcp/pdcp_tx_benchmark.cpp | 52 ++++++++++++++------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/tests/benchmarks/pdcp/pdcp_tx_benchmark.cpp b/tests/benchmarks/pdcp/pdcp_tx_benchmark.cpp index 6e9decc3a0..a5e872fe04 100644 --- a/tests/benchmarks/pdcp/pdcp_tx_benchmark.cpp +++ b/tests/benchmarks/pdcp/pdcp_tx_benchmark.cpp @@ -38,32 +38,46 @@ struct bench_params { bool print_timing_info = false; }; -static void usage(const char* prog, const bench_params& params, int algo) +struct app_params { + int algo = -1; + std::string log_level = "error"; + std::string log_filename = "stdout"; +}; + +static void usage(const char* prog, const bench_params& params, const app_params app) { fmt::print("Usage: {} [-R repetitions] [-t timing information]\n", prog); - fmt::print("\t-a Security algorithm to use [Default {}, valid {{-1,0,1,2,3}}]\n", algo); + fmt::print("\t-a Security algorithm to use [Default {}, valid {{-1,0,1,2,3}}]\n", app.algo); fmt::print("\t-t Print timing information [Default {}]\n", params.print_timing_info); fmt::print("\t-R Repetitions [Default {}]\n", params.nof_repetitions); + fmt::print("\t-l Log level to use [Default {}, valid {{error, warning, info, debug}}]\n", app.log_level); + fmt::print("\t-f Log filename to use [Default {}]\n", app.log_filename); fmt::print("\t-h Show this message\n"); } -static void parse_args(int argc, char** argv, bench_params& params, int& algo) +static void parse_args(int argc, char** argv, bench_params& params, app_params& app) { int opt = 0; - while ((opt = getopt(argc, argv, "a:R:th")) != -1) { + while ((opt = getopt(argc, argv, "a:R:l:f:th")) != -1) { switch (opt) { case 'R': params.nof_repetitions = std::strtol(optarg, nullptr, 10); break; case 'a': - algo = std::strtol(optarg, nullptr, 10); + app.algo = std::strtol(optarg, nullptr, 10); break; case 't': params.print_timing_info = true; break; + case 'l': + app.log_level = std::string(optarg); + break; + case 'f': + app.log_filename = std::string(optarg); + break; case 'h': default: - usage(argv[0], params, algo); + usage(argv[0], params, app); exit(0); } } @@ -113,9 +127,6 @@ void benchmark_pdcp_tx(bench_params params, // Create test frame pdcp_tx_gen_frame frame = {}; - auto& logger = srslog::fetch_basic_logger("PDCP"); - logger.set_level(srslog::str_to_basic_level("warning")); - // Create PDCP entities std::unique_ptr pdcp_tx = std::make_unique(0, drb_id_t::drb1, config, frame, frame, timer_factory{timers, worker}); @@ -160,8 +171,8 @@ int run_benchmark(bench_params params, int algo) } fmt::print("------ Benchmarcking: NIA{} NEA{} ------\n", algo, algo); - security::integrity_algorithm int_algo = static_cast(algo); - security::ciphering_algorithm ciph_algo = static_cast(algo); + auto int_algo = static_cast(algo); + auto ciph_algo = static_cast(algo); if (algo == 0) { benchmark_pdcp_tx(params, @@ -180,15 +191,22 @@ int run_benchmark(bench_params params, int algo) int main(int argc, char** argv) { + bench_params params{}; + app_params app_params{}; + parse_args(argc, argv, params, app_params); + srslog::init(); - srslog::fetch_basic_logger("PDCP").set_level(srslog::basic_levels::error); - int algo = -1; - bench_params params{}; - parse_args(argc, argv, params, algo); + srslog::sink* log_sink = (app_params.log_filename == "stdout") ? srslog::create_stdout_sink() + : srslog::create_file_sink(app_params.log_filename); + if (log_sink == nullptr) { + return -1; + } + srslog::set_default_sink(*log_sink); + srslog::fetch_basic_logger("PDCP").set_level(srslog::str_to_basic_level(app_params.log_level)); - if (algo != -1) { - run_benchmark(params, algo); + if (app_params.algo != -1) { + run_benchmark(params, app_params.algo); } else { for (unsigned i = 0; i < 4; i++) { run_benchmark(params, i); From 0ee55faac6852a6d96c7ed6ba63fa124bd580802 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Mon, 26 Feb 2024 17:44:37 +0000 Subject: [PATCH 043/140] pdcp: add logging option to rx benchmark --- tests/benchmarks/pdcp/pdcp_rx_benchmark.cpp | 49 +++++++++++++++------ tests/benchmarks/pdcp/pdcp_tx_benchmark.cpp | 2 +- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/tests/benchmarks/pdcp/pdcp_rx_benchmark.cpp b/tests/benchmarks/pdcp/pdcp_rx_benchmark.cpp index d1d7e76fa1..7cdb5e91f0 100644 --- a/tests/benchmarks/pdcp/pdcp_rx_benchmark.cpp +++ b/tests/benchmarks/pdcp/pdcp_rx_benchmark.cpp @@ -62,31 +62,45 @@ struct bench_params { bool print_timing_info = false; }; -static void usage(const char* prog, const bench_params& params, int algo) +struct app_params { + int algo = -1; + std::string log_level = "error"; + std::string log_filename = "stdout"; +}; + +static void usage(const char* prog, const bench_params& params, const app_params& app) { fmt::print("Usage: {} [-R repetitions] [-s silent]\n", prog); - fmt::print("\t-a Security algorithm to use [Default {}, valid {{-1,0,1,2,3}}]\n", algo); + fmt::print("\t-a Security algorithm to use [Default {}, valid {{-1,0,1,2,3}}]\n", app.algo); fmt::print("\t-R Repetitions [Default {}]\n", params.nof_repetitions); + fmt::print("\t-l Log level to use [Default {}, valid {{error, warning, info, debug}}]\n", app.log_level); + fmt::print("\t-f Log filename to use [Default {}]\n", app.log_filename); fmt::print("\t-h Show this message\n"); } -static void parse_args(int argc, char** argv, bench_params& params, int& algo) +static void parse_args(int argc, char** argv, bench_params& params, app_params& app) { int opt = 0; - while ((opt = getopt(argc, argv, "a:R:th")) != -1) { + while ((opt = getopt(argc, argv, "a:R:l:f:th")) != -1) { switch (opt) { case 'R': params.nof_repetitions = std::strtol(optarg, nullptr, 10); break; case 'a': - algo = std::strtol(optarg, nullptr, 10); + app.algo = std::strtol(optarg, nullptr, 10); break; case 't': params.print_timing_info = true; break; + case 'l': + app.log_level = std::string(optarg); + break; + case 'f': + app.log_filename = std::string(optarg); + break; case 'h': default: - usage(argv[0], params, algo); + usage(argv[0], params, app); exit(0); } } @@ -252,20 +266,27 @@ int run_benchmark(bench_params params, int algo) int main(int argc, char** argv) { - srslog::init(); - srslog::fetch_basic_logger("PDCP").set_level(srslog::basic_levels::error); - - int algo = -1; bench_params params{}; - parse_args(argc, argv, params, algo); + app_params app_params{}; + parse_args(argc, argv, params, app_params); + + srslog::init(); + srslog::sink* log_sink = (app_params.log_filename == "stdout") ? srslog::create_stdout_sink() + : srslog::create_file_sink(app_params.log_filename); + if (log_sink == nullptr) { + return -1; + } + srslog::set_default_sink(*log_sink); + srslog::fetch_basic_logger("PDCP").set_level(srslog::str_to_basic_level(app_params.log_level)); - if (algo != -1 && algo != 0 && algo != 1 && algo != 2 && algo != 3) { + if (app_params.algo != -1 && app_params.algo != 0 && app_params.algo != 1 && app_params.algo != 2 && + app_params.algo != 3) { fmt::print("Unsupported algorithm. Use -1, 0, 1, 2 or 3.\n"); return -1; } - if (algo != -1) { - run_benchmark(params, algo); + if (app_params.algo != -1) { + run_benchmark(params, app_params.algo); } else { for (unsigned i = 0; i < 4; i++) { run_benchmark(params, i); diff --git a/tests/benchmarks/pdcp/pdcp_tx_benchmark.cpp b/tests/benchmarks/pdcp/pdcp_tx_benchmark.cpp index a5e872fe04..2331a6908f 100644 --- a/tests/benchmarks/pdcp/pdcp_tx_benchmark.cpp +++ b/tests/benchmarks/pdcp/pdcp_tx_benchmark.cpp @@ -44,7 +44,7 @@ struct app_params { std::string log_filename = "stdout"; }; -static void usage(const char* prog, const bench_params& params, const app_params app) +static void usage(const char* prog, const bench_params& params, const app_params& app) { fmt::print("Usage: {} [-R repetitions] [-t timing information]\n", prog); fmt::print("\t-a Security algorithm to use [Default {}, valid {{-1,0,1,2,3}}]\n", app.algo); From 788543db73c86ed9cf549069edc0fc0855611400 Mon Sep 17 00:00:00 2001 From: asaezper Date: Wed, 28 Feb 2024 10:18:22 +0100 Subject: [PATCH 044/140] ci,e2e: zmq split tests in more job --- .gitlab/ci/e2e.yml | 10 +++++++++- .gitlab/ci/schedules.yml | 2 +- tests/e2e/tests/iperf.py | 10 ++++++---- tests/e2e/tests/ping.py | 2 +- tests/e2e/tests/reestablishment.py | 2 +- tests/e2e/tests/steps/stub.py | 2 +- 6 files changed, 19 insertions(+), 9 deletions(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index cd5c2762dc..7081b5d797 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -267,7 +267,15 @@ amari 32UE: - *retina-needs parallel: matrix: - - KEYWORDS: ["attach_detach", "ping", "iperf and udp", "iperf and tcp"] + - KEYWORDS: + [ + "attach_detach", + "ping", + "iperf and udp and band:3", + "iperf and udp and not band:3", + "iperf and tcp and band:3", + "iperf and tcp and not band:3", + ] amari 32UE [reestablishment]: extends: .zmq diff --git a/.gitlab/ci/schedules.yml b/.gitlab/ci/schedules.yml index 90c605717c..ada7e26243 100644 --- a/.gitlab/ci/schedules.yml +++ b/.gitlab/ci/schedules.yml @@ -35,7 +35,7 @@ Nightly Build Unit Tests: value: "#ci_gnb" Nightly E2E Tests: - cron: "15 23 * * 0-5" + cron: "00 23 * * 0-5" cron_timezone: "Europe/Madrid" ref: dev variables: diff --git a/tests/e2e/tests/iperf.py b/tests/e2e/tests/iperf.py index 5022063715..f47b38410d 100644 --- a/tests/e2e/tests/iperf.py +++ b/tests/e2e/tests/iperf.py @@ -348,7 +348,7 @@ def test_android_hp( (param(41, 30, 20, id="band:%s-scs:%s-bandwidth:%s"),), ) @mark.zmq_4x4_mimo -@mark.flaky(reruns=1, only_rerun=["5GC crashed"]) +@mark.flaky(reruns=2, only_rerun=["failed to start", "Attach timeout reached", "5GC crashed"]) # pylint: disable=too-many-arguments def test_zmq_4x4_mimo( retina_manager: RetinaTestManager, @@ -470,14 +470,16 @@ def test_zmq_smoke( param(3, 15, 5, MEDIUM_BITRATE, False, id=ZMQ_ID), param(3, 15, 10, MEDIUM_BITRATE, False, id=ZMQ_ID), param(3, 15, 20, MEDIUM_BITRATE, False, id=ZMQ_ID), - param(3, 15, 50, MEDIUM_BITRATE, True, id=ZMQ_ID), + param(3, 15, 50, MEDIUM_BITRATE, False, id=ZMQ_ID), param(41, 30, 10, MEDIUM_BITRATE, False, id=ZMQ_ID), param(41, 30, 20, MEDIUM_BITRATE, False, id=ZMQ_ID), - param(41, 30, 50, MEDIUM_BITRATE, True, id=ZMQ_ID), + param(41, 30, 50, MEDIUM_BITRATE, False, id=ZMQ_ID), ), ) @mark.zmq -@mark.flaky(reruns=1, only_rerun=["failed to start", "iperf did not achieve the expected data rate"]) +@mark.flaky( + reruns=2, only_rerun=["failed to start", "Attach timeout reached", "iperf did not achieve the expected data rate"] +) # pylint: disable=too-many-arguments def test_zmq( retina_manager: RetinaTestManager, diff --git a/tests/e2e/tests/ping.py b/tests/e2e/tests/ping.py index ebc3d45efc..9c89aa1505 100644 --- a/tests/e2e/tests/ping.py +++ b/tests/e2e/tests/ping.py @@ -140,7 +140,7 @@ def test_android_hp( ), ) @mark.zmq -@mark.flaky(reruns=2, only_rerun=["Some packages got lost"]) +@mark.flaky(reruns=2, only_rerun=["failed to start", "Attach timeout reached", "Some packages got lost"]) # pylint: disable=too-many-arguments def test_zmq( retina_manager: RetinaTestManager, diff --git a/tests/e2e/tests/reestablishment.py b/tests/e2e/tests/reestablishment.py index f649faf280..5eb2b6351f 100644 --- a/tests/e2e/tests/reestablishment.py +++ b/tests/e2e/tests/reestablishment.py @@ -33,7 +33,7 @@ ), ) @mark.zmq -@mark.flaky(reruns=5, only_rerun=["failed to start", "StatusCode.ABORTED"]) +@mark.flaky(reruns=2, only_rerun=["failed to start", "Attach timeout reached", "StatusCode.ABORTED"]) # pylint: disable=too-many-arguments def test_zmq_reestablishment( retina_manager: RetinaTestManager, diff --git a/tests/e2e/tests/steps/stub.py b/tests/e2e/tests/steps/stub.py index 9744f6095c..e96f88b69d 100644 --- a/tests/e2e/tests/steps/stub.py +++ b/tests/e2e/tests/steps/stub.py @@ -43,7 +43,7 @@ UE_STARTUP_TIMEOUT: int = RF_MAX_TIMEOUT GNB_STARTUP_TIMEOUT: int = 5 # GNB delay (we wait x seconds and check it's still alive). UE later and has a big timeout FIVEGC_STARTUP_TIMEOUT: int = RF_MAX_TIMEOUT -ATTACH_TIMEOUT: int = 5 * 60 +ATTACH_TIMEOUT: int = 1 * 60 # pylint: disable=too-many-arguments,too-many-locals From 16001acc0131a8b0e2e8ada9c1014d22def33fb3 Mon Sep 17 00:00:00 2001 From: sauka Date: Mon, 26 Feb 2024 12:29:02 +0200 Subject: [PATCH 045/140] gnb: fix neon compilation in srsvec --- lib/srsvec/compare.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/srsvec/compare.cpp b/lib/srsvec/compare.cpp index 0006fa7f45..51ff140081 100644 --- a/lib/srsvec/compare.cpp +++ b/lib/srsvec/compare.cpp @@ -45,7 +45,7 @@ const char* srsran::srsvec::detail::find(span input, const char* val // Load 16 consecutive words starting at index. int8x16_t simd_input = vld1q_s8(reinterpret_cast(input.data() + index)); // Compare the 16 words with the value. - uint8x16_t mask_u8 = vceqq_s8(vdupq_n_s8((int8_t)value), simd_input); + uint8x16_t mask_u8 = vceqq_s8(vdupq_n_s8(int8_t(v)), simd_input); uint8_t mask = vmaxvq_u8(mask_u8); if (mask != 0) { found = true; @@ -57,7 +57,7 @@ const char* srsran::srsvec::detail::find(span input, const char* val // Load 8 consecutive words starting at index. int8x8_t simd_input = vld1_s8(reinterpret_cast(input.data() + index)); // Compare the 8 words with the value. - uint8x8_t mask_u8 = vceq_s8(vdup_n_s8((int8_t)value), simd_input); + uint8x8_t mask_u8 = vceq_s8(vdup_n_s8(int8_t(v)), simd_input); uint8_t mask = vmaxv_u8(mask_u8); if (mask != 0) { break; From a86fdd3a314fe2226bc7db5ce3d758084a3c995c Mon Sep 17 00:00:00 2001 From: asaezper Date: Thu, 29 Feb 2024 11:53:01 +0100 Subject: [PATCH 046/140] ci,e2e: no retries on amari 32 ue tests --- tests/e2e/tests/iperf.py | 6 +++--- tests/e2e/tests/ping.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/e2e/tests/iperf.py b/tests/e2e/tests/iperf.py index f47b38410d..c621b033a8 100644 --- a/tests/e2e/tests/iperf.py +++ b/tests/e2e/tests/iperf.py @@ -477,9 +477,9 @@ def test_zmq_smoke( ), ) @mark.zmq -@mark.flaky( - reruns=2, only_rerun=["failed to start", "Attach timeout reached", "iperf did not achieve the expected data rate"] -) +# @mark.flaky( +# reruns=2, only_rerun=["failed to start", "Attach timeout reached", "iperf did not achieve the expected data rate"] +# ) # pylint: disable=too-many-arguments def test_zmq( retina_manager: RetinaTestManager, diff --git a/tests/e2e/tests/ping.py b/tests/e2e/tests/ping.py index 9c89aa1505..a8c366fa19 100644 --- a/tests/e2e/tests/ping.py +++ b/tests/e2e/tests/ping.py @@ -140,7 +140,7 @@ def test_android_hp( ), ) @mark.zmq -@mark.flaky(reruns=2, only_rerun=["failed to start", "Attach timeout reached", "Some packages got lost"]) +# @mark.flaky(reruns=2, only_rerun=["failed to start", "Attach timeout reached", "Some packages got lost"]) # pylint: disable=too-many-arguments def test_zmq( retina_manager: RetinaTestManager, From 61c5405ac5976a29d53b3fe4d6e3f574f1abecd5 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Thu, 29 Feb 2024 10:53:32 +0000 Subject: [PATCH 047/140] pdcp: improve key logging --- include/srsran/security/security.h | 32 ++++++++++++++++++++++++++++++ lib/pdcp/pdcp_entity_rx.h | 4 ++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/include/srsran/security/security.h b/include/srsran/security/security.h index 646f5d52ae..12529d4a2d 100644 --- a/include/srsran/security/security.h +++ b/include/srsran/security/security.h @@ -418,4 +418,36 @@ struct formatter { } }; +// Key formatting +template <> +struct formatter { + template + auto parse(ParseContext& ctx) -> decltype(ctx.begin()) + { + return ctx.begin(); + } + + template + auto format(const srsran::security::sec_128_key& key, FormatContext& ctx) + -> decltype(std::declval().out()) + { + return format_to(ctx.out(), "\n\t{:02x}", fmt::join(key, " ")); + } +}; + +template <> +struct formatter { + template + auto parse(ParseContext& ctx) -> decltype(ctx.begin()) + { + return ctx.begin(); + } + + template + auto format(const srsran::security::sec_128_key& key, FormatContext& ctx) + -> decltype(std::declval().out()) + { + return format_to(ctx.out(), "\n\t{:02x}", fmt::join(key.begin(), key.end(), " ")); + } +}; } // namespace fmt diff --git a/lib/pdcp/pdcp_entity_rx.h b/lib/pdcp/pdcp_entity_rx.h index ed1de2904d..5a41e45217 100644 --- a/lib/pdcp/pdcp_entity_rx.h +++ b/lib/pdcp/pdcp_entity_rx.h @@ -114,9 +114,9 @@ class pdcp_entity_rx final : public pdcp_entity_tx_rx_base, logger.log_info( "Security configured: NIA{} NEA{} domain={}", sec_cfg.integ_algo, sec_cfg.cipher_algo, sec_cfg.domain); if (sec_cfg.k_128_int.has_value()) { - logger.log_info(sec_cfg.k_128_int.value().data(), 16, "128 K_int"); + logger.log_info("128 K_int: {}", sec_cfg.k_128_int); } - logger.log_info(sec_cfg.k_128_enc.data(), 16, "128 K_enc"); + logger.log_info("128 K_enc: {}", sec_cfg.k_128_enc); } void set_integrity_protection(security::integrity_enabled integrity_enabled_) final From fdb4b89a72e12ac3d3ffa9eb1ab71326790d387e Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Thu, 29 Feb 2024 12:10:32 +0000 Subject: [PATCH 048/140] sec: improve key logs --- lib/security/security.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/security/security.cpp b/lib/security/security.cpp index 46d7070d5c..7c9ebee573 100644 --- a/lib/security/security.cpp +++ b/lib/security/security.cpp @@ -75,7 +75,7 @@ void security_context::generate_as_keys() security::generate_k_up(as_keys.k_up_enc, as_keys.k_up_int, k, sel_algos.cipher_algo, sel_algos.integ_algo); logger.debug(k.data(), k.size(), "K_gNB"); - logger.debug(as_keys.k_rrc_int.data(), as_keys.k_rrc_int.size(), "RRC Integrity Key"); + logger.debug("RRC Integrity Key: {}", as_keys.k_rrc_int); logger.debug(as_keys.k_rrc_enc.data(), as_keys.k_rrc_enc.size(), "RRC Encryption Key"); logger.debug(as_keys.k_up_int.data(), as_keys.k_up_int.size(), "UP Integrity Key"); logger.debug(as_keys.k_up_enc.data(), as_keys.k_up_enc.size(), "UP Encryption Key"); From e2a6f1bae9edbc3d9f251fe2a6be87acfdae675f Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Thu, 29 Feb 2024 13:15:19 +0000 Subject: [PATCH 049/140] sec: fix key logging --- include/srsran/security/security.h | 6 +++--- lib/pdcp/pdcp_entity_tx.h | 4 ++-- lib/security/security.cpp | 12 ++++++------ 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/srsran/security/security.h b/include/srsran/security/security.h index 12529d4a2d..7f301ad302 100644 --- a/include/srsran/security/security.h +++ b/include/srsran/security/security.h @@ -444,10 +444,10 @@ struct formatter { } template - auto format(const srsran::security::sec_128_key& key, FormatContext& ctx) - -> decltype(std::declval().out()) + auto format(const srsran::security::sec_key& key, FormatContext& ctx) -> decltype(std::declval().out()) { - return format_to(ctx.out(), "\n\t{:02x}", fmt::join(key.begin(), key.end(), " ")); + format_to(ctx.out(), "\n\t{:02x}", fmt::join(key.begin(), key.begin() + 16, " ")); + return format_to(ctx.out(), "\n\t{:02x}", fmt::join(key.begin() + 16, key.end(), " ")); } }; } // namespace fmt diff --git a/lib/pdcp/pdcp_entity_tx.h b/lib/pdcp/pdcp_entity_tx.h index 19e9a57075..e9410e12eb 100644 --- a/lib/pdcp/pdcp_entity_tx.h +++ b/lib/pdcp/pdcp_entity_tx.h @@ -167,9 +167,9 @@ class pdcp_entity_tx final : public pdcp_entity_tx_rx_base, logger.log_info( "Security configured: NIA{} NEA{} domain={}", sec_cfg.integ_algo, sec_cfg.cipher_algo, sec_cfg.domain); if (sec_cfg.k_128_int.has_value()) { - logger.log_info(sec_cfg.k_128_int.value().data(), 16, "128 K_int"); + logger.log_info("128 K_int: {}", sec_cfg.k_128_int.value()); } - logger.log_info(sec_cfg.k_128_enc.data(), 16, "128 K_enc"); + logger.log_info("128 K_enc: {}", sec_cfg.k_128_enc); }; void set_integrity_protection(security::integrity_enabled integrity_enabled_) final diff --git a/lib/security/security.cpp b/lib/security/security.cpp index 7c9ebee573..b5191536cc 100644 --- a/lib/security/security.cpp +++ b/lib/security/security.cpp @@ -74,17 +74,17 @@ void security_context::generate_as_keys() // Generate K_up_enc and K_up_int security::generate_k_up(as_keys.k_up_enc, as_keys.k_up_int, k, sel_algos.cipher_algo, sel_algos.integ_algo); - logger.debug(k.data(), k.size(), "K_gNB"); - logger.debug("RRC Integrity Key: {}", as_keys.k_rrc_int); - logger.debug(as_keys.k_rrc_enc.data(), as_keys.k_rrc_enc.size(), "RRC Encryption Key"); - logger.debug(as_keys.k_up_int.data(), as_keys.k_up_int.size(), "UP Integrity Key"); - logger.debug(as_keys.k_up_enc.data(), as_keys.k_up_enc.size(), "UP Encryption Key"); + logger.info("K_gNB: {}", k); + logger.info("RRC Integrity Key: {}", as_keys.k_rrc_int); + logger.info("RRC Encryption Key: {}", as_keys.k_rrc_enc); + logger.info("UP Integrity Key: {}", as_keys.k_up_int); + logger.info("UP Encryption Key: {}", as_keys.k_up_enc); } void security_context::horizontal_key_derivation(pci_t target_pci, unsigned target_ssb_arfcn) { logger.info("Regenerating KgNB with PCI={}, SSB-ARFCN={}", target_pci, target_ssb_arfcn); - logger.info(k.data(), k.size(), "Old K_gNB (k_gnb)"); + logger.info("Old K_gNB: {}", k); // Generate K_NG-RAN* sec_key k_ng_ran_star; From 138cc7750e623dfc5479761f40bd1cc923c87320 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Tue, 27 Feb 2024 17:45:12 +0000 Subject: [PATCH 050/140] f1u: add exec transition to CU-UP --- include/srsran/f1u/cu_up/f1u_bearer_factory.h | 1 + include/srsran/f1u/cu_up/f1u_gateway.h | 1 + .../f1u/local_connector/f1u_local_connector.h | 1 + lib/cu_up/pdu_session_manager_impl.cpp | 15 +++++++++++++-- lib/cu_up/pdu_session_manager_impl.h | 4 ++++ lib/cu_up/ue_context.h | 16 ++++++++++++---- lib/cu_up/ue_manager.cpp | 15 ++++++++++----- lib/f1u/cu_up/f1u_bearer_factory.cpp | 12 ++++++++++-- lib/f1u/cu_up/f1u_bearer_impl.cpp | 11 +++++++++++ lib/f1u/cu_up/f1u_bearer_impl.h | 4 ++++ lib/f1u/local_connector/f1u_local_connector.cpp | 3 ++- .../integrationtests/rlc/rlc_stress_test_args.h | 2 +- tests/unittests/cu_up/cu_up_test_helpers.h | 1 + tests/unittests/cu_up/pdu_session_manager_test.h | 2 ++ .../unittests/f1u/common/f1u_connector_test.cpp | 6 +++--- .../f1u/cu_up/f1u_cu_up_bearer_test.cpp | 1 + 16 files changed, 77 insertions(+), 18 deletions(-) diff --git a/include/srsran/f1u/cu_up/f1u_bearer_factory.h b/include/srsran/f1u/cu_up/f1u_bearer_factory.h index fe6986e9f3..c7a9f1d845 100644 --- a/include/srsran/f1u/cu_up/f1u_bearer_factory.h +++ b/include/srsran/f1u/cu_up/f1u_bearer_factory.h @@ -29,6 +29,7 @@ std::unique_ptr create_f1u_bearer(uint32_t ue_ f1u_rx_delivery_notifier& rx_delivery_notifier, f1u_rx_sdu_notifier& rx_sdu_notifier, timer_factory timers, + task_executor& ul_exec, f1u_bearer_disconnector& disconnector); } // namespace srs_cu_up diff --git a/include/srsran/f1u/cu_up/f1u_gateway.h b/include/srsran/f1u/cu_up/f1u_gateway.h index 9bd7dca343..aad2103b27 100644 --- a/include/srsran/f1u/cu_up/f1u_gateway.h +++ b/include/srsran/f1u/cu_up/f1u_gateway.h @@ -37,6 +37,7 @@ class f1u_cu_up_gateway : public srs_cu_up::f1u_bearer_disconnector const up_transport_layer_info& ul_up_tnl_info, srs_cu_up::f1u_rx_delivery_notifier& rx_delivery_notifier, srs_cu_up::f1u_rx_sdu_notifier& rx_sdu_notifier, + task_executor& ul_exec, timer_factory timers) = 0; virtual void attach_dl_teid(const up_transport_layer_info& ul_up_tnl_info, diff --git a/include/srsran/f1u/local_connector/f1u_local_connector.h b/include/srsran/f1u/local_connector/f1u_local_connector.h index 8991142155..4fdb8a1704 100644 --- a/include/srsran/f1u/local_connector/f1u_local_connector.h +++ b/include/srsran/f1u/local_connector/f1u_local_connector.h @@ -65,6 +65,7 @@ class f1u_local_connector final : public srs_du::f1u_du_gateway, public f1u_cu_u const up_transport_layer_info& ul_up_tnl_info, srs_cu_up::f1u_rx_delivery_notifier& rx_delivery_notifier, srs_cu_up::f1u_rx_sdu_notifier& rx_sdu_notifier, + task_executor& ul_exec, timer_factory timers) override; void attach_dl_teid(const up_transport_layer_info& ul_up_tnl_info, diff --git a/lib/cu_up/pdu_session_manager_impl.cpp b/lib/cu_up/pdu_session_manager_impl.cpp index 6f4ebacdfc..78dda7faf3 100644 --- a/lib/cu_up/pdu_session_manager_impl.cpp +++ b/lib/cu_up/pdu_session_manager_impl.cpp @@ -34,6 +34,8 @@ pdu_session_manager_impl::pdu_session_manager_impl(ue_index_t gtpu_tunnel_tx_upper_layer_notifier& gtpu_tx_notifier_, gtpu_demux_ctrl& gtpu_rx_demux_, task_executor& ue_dl_exec_, + task_executor& ue_ul_exec_, + task_executor& ue_ctrl_exec_, dlt_pcap& gtpu_pcap_) : ue_index(ue_index_), qos_cfg(std::move(qos_cfg_)), @@ -47,9 +49,12 @@ pdu_session_manager_impl::pdu_session_manager_impl(ue_index_t f1u_teid_allocator(f1u_teid_allocator_), gtpu_rx_demux(gtpu_rx_demux_), ue_dl_exec(ue_dl_exec_), + ue_ul_exec(ue_ul_exec_), + ue_ctrl_exec(ue_ctrl_exec_), gtpu_pcap(gtpu_pcap_), f1u_gw(f1u_gw_) { + (void)ue_ctrl_exec; } drb_setup_result pdu_session_manager_impl::handle_drb_to_setup_item(pdu_session& new_session, @@ -186,6 +191,7 @@ drb_setup_result pdu_session_manager_impl::handle_drb_to_setup_item(pdu_session& f1u_ul_tunnel_addr, new_drb->f1u_to_pdcp_adapter, new_drb->f1u_to_pdcp_adapter, + ue_ul_exec, timers); new_drb->f1u_ul_teid = f1u_ul_teid; drb_result.gtp_tunnel = f1u_ul_tunnel_addr; @@ -367,8 +373,13 @@ pdu_session_manager_impl::modify_pdu_session(const e1ap_pdu_session_res_to_modif f1u_ul_tunnel_addr.gtp_teid = drb->f1u_ul_teid; // create new F1-U and connect it. This will automatically disconnect the old F1-U. - drb->f1u = f1u_gw.create_cu_bearer( - ue_index, drb->drb_id, f1u_ul_tunnel_addr, drb->f1u_to_pdcp_adapter, drb->f1u_to_pdcp_adapter, timers); + drb->f1u = f1u_gw.create_cu_bearer(ue_index, + drb->drb_id, + f1u_ul_tunnel_addr, + drb->f1u_to_pdcp_adapter, + drb->f1u_to_pdcp_adapter, + ue_dl_exec, + timers); drb_iter->second->pdcp_to_f1u_adapter.disconnect_f1u(); drb_result.gtp_tunnel = f1u_ul_tunnel_addr; diff --git a/lib/cu_up/pdu_session_manager_impl.h b/lib/cu_up/pdu_session_manager_impl.h index 198b206cd7..0c0bdedfaa 100644 --- a/lib/cu_up/pdu_session_manager_impl.h +++ b/lib/cu_up/pdu_session_manager_impl.h @@ -43,6 +43,8 @@ class pdu_session_manager_impl final : public pdu_session_manager_ctrl gtpu_tunnel_tx_upper_layer_notifier& gtpu_tx_notifier_, gtpu_demux_ctrl& gtpu_rx_demux_, task_executor& ue_dl_exec_, + task_executor& ue_ul_exec_, + task_executor& ue_ctrl_exec_, dlt_pcap& gtpu_pcap_); pdu_session_setup_result setup_pdu_session(const e1ap_pdu_session_res_to_setup_item& session) override; @@ -75,6 +77,8 @@ class pdu_session_manager_impl final : public pdu_session_manager_ctrl gtpu_teid_pool& f1u_teid_allocator; gtpu_demux_ctrl& gtpu_rx_demux; task_executor& ue_dl_exec; + task_executor& ue_ul_exec; + task_executor& ue_ctrl_exec; dlt_pcap& gtpu_pcap; f1u_cu_up_gateway& f1u_gw; std::map> pdu_sessions; // key is pdu_session_id diff --git a/lib/cu_up/ue_context.h b/lib/cu_up/ue_context.h index 5dd3cc724a..318bb9cba7 100644 --- a/lib/cu_up/ue_context.h +++ b/lib/cu_up/ue_context.h @@ -40,7 +40,9 @@ class ue_context : public pdu_session_manager_ctrl e1ap_control_message_handler& e1ap_, network_interface_config& net_config_, n3_interface_config& n3_config_, - std::unique_ptr> ue_exec_, + std::unique_ptr> ue_dl_exec_, + std::unique_ptr> ue_ul_exec_, + std::unique_ptr> ue_ctrl_exec_, timer_factory timers_, f1u_cu_up_gateway& f1u_gw_, gtpu_teid_pool& f1u_teid_allocator_, @@ -63,9 +65,13 @@ class ue_context : public pdu_session_manager_ctrl f1u_teid_allocator_, gtpu_tx_notifier_, gtpu_rx_demux_, - *ue_exec_, + *ue_dl_exec_, + *ue_ul_exec_, + *ue_ctrl_exec_, gtpu_pcap), - ue_exec(std::move(ue_exec_)), + ue_dl_exec(std::move(ue_dl_exec_)), + ue_ul_exec(std::move(ue_ul_exec_)), + ue_ctrl_exec(std::move(ue_ctrl_exec_)), timers(timers_) { if (cfg.activity_level == activity_notification_level_t::ue) { @@ -110,7 +116,9 @@ class ue_context : public pdu_session_manager_ctrl e1ap_control_message_handler& e1ap; pdu_session_manager_impl pdu_session_manager; - std::unique_ptr> ue_exec; + std::unique_ptr> ue_dl_exec; + std::unique_ptr> ue_ul_exec; + std::unique_ptr> ue_ctrl_exec; timer_factory timers; unique_timer ue_inactivity_timer; diff --git a/lib/cu_up/ue_manager.cpp b/lib/cu_up/ue_manager.cpp index 955c7295d3..e7665c0c85 100644 --- a/lib/cu_up/ue_manager.cpp +++ b/lib/cu_up/ue_manager.cpp @@ -57,8 +57,12 @@ ue_context* ue_manager::add_ue(const ue_context_cfg& ue_cfg) return nullptr; } - // Create UE executor - std::unique_ptr> ue_exec = exec_pool.create_dl_pdu_executor(); + // Create UE executors + // TODO, these should be created within the same function, so that UL, DL and CTRL executors + // can point to the same executor. + std::unique_ptr> ue_dl_exec = exec_pool.create_dl_pdu_executor(); + std::unique_ptr> ue_ul_exec = exec_pool.create_ul_pdu_executor(); + std::unique_ptr> ue_ctrl_exec = exec_pool.create_ctrl_executor(); // Create UE object std::unique_ptr new_ctx = std::make_unique(new_idx, @@ -66,8 +70,10 @@ ue_context* ue_manager::add_ue(const ue_context_cfg& ue_cfg) e1ap, net_config, n3_config, - std::move(ue_exec), - timer_factory{timers, *ue_exec}, + std::move(ue_dl_exec), + std::move(ue_ul_exec), + std::move(ue_ctrl_exec), + timer_factory{timers, *ue_ctrl_exec}, f1u_gw, f1u_teid_allocator, gtpu_tx_notifier, @@ -90,7 +96,6 @@ void ue_manager::remove_ue(ue_index_t ue_index) ue_db.erase(ue_index); logger.info("Removed ue_index={}", ue_index); - return; } ue_index_t ue_manager::get_next_ue_index() diff --git a/lib/f1u/cu_up/f1u_bearer_factory.cpp b/lib/f1u/cu_up/f1u_bearer_factory.cpp index 9c6cc9e3bd..a58c0f3a1b 100644 --- a/lib/f1u/cu_up/f1u_bearer_factory.cpp +++ b/lib/f1u/cu_up/f1u_bearer_factory.cpp @@ -22,9 +22,17 @@ std::unique_ptr srsran::srs_cu_up::create_f1u_bearer(uint32_t f1u_rx_delivery_notifier& rx_delivery_notifier, f1u_rx_sdu_notifier& rx_sdu_notifier, timer_factory timers, + task_executor& ul_exec, f1u_bearer_disconnector& disconnector) { - auto bearer = std::make_unique( - ue_index, drb_id, ul_up_tnl_info, tx_pdu_notifier, rx_delivery_notifier, rx_sdu_notifier, timers, disconnector); + auto bearer = std::make_unique(ue_index, + drb_id, + ul_up_tnl_info, + tx_pdu_notifier, + rx_delivery_notifier, + rx_sdu_notifier, + timers, + ul_exec, + disconnector); return bearer; } diff --git a/lib/f1u/cu_up/f1u_bearer_impl.cpp b/lib/f1u/cu_up/f1u_bearer_impl.cpp index c05384964f..1c1984d548 100644 --- a/lib/f1u/cu_up/f1u_bearer_impl.cpp +++ b/lib/f1u/cu_up/f1u_bearer_impl.cpp @@ -21,6 +21,7 @@ f1u_bearer_impl::f1u_bearer_impl(uint32_t ue_index, f1u_rx_delivery_notifier& rx_delivery_notifier_, f1u_rx_sdu_notifier& rx_sdu_notifier_, timer_factory timers, + task_executor& ul_exec_, f1u_bearer_disconnector& disconnector_) : logger("CU-F1-U", {ue_index, drb_id_, ul_tnl_info_}), tx_pdu_notifier(tx_pdu_notifier_), @@ -28,6 +29,7 @@ f1u_bearer_impl::f1u_bearer_impl(uint32_t ue_index, rx_sdu_notifier(rx_sdu_notifier_), disconnector(disconnector_), ul_tnl_info(ul_tnl_info_), + ul_exec(ul_exec_), dl_notif_timer(timers.create_timer()) { dl_notif_timer.set(std::chrono::milliseconds(f1u_dl_notif_time_ms), @@ -35,6 +37,15 @@ f1u_bearer_impl::f1u_bearer_impl(uint32_t ue_index, } void f1u_bearer_impl::handle_pdu(nru_ul_message msg) +{ + auto fn = [this, m = std::move(msg)]() mutable { handle_pdu_impl(std::move(m)); }; + + if (not ul_exec.execute(std::move(fn))) { + logger.log_warning("Dropped F1-U PDU, queue is full."); + } +} + +void f1u_bearer_impl::handle_pdu_impl(nru_ul_message msg) { logger.log_debug("F1-U bearer received PDU"); // handle T-PDU diff --git a/lib/f1u/cu_up/f1u_bearer_impl.h b/lib/f1u/cu_up/f1u_bearer_impl.h index 8d72c93d1c..e2a4c79e20 100644 --- a/lib/f1u/cu_up/f1u_bearer_impl.h +++ b/lib/f1u/cu_up/f1u_bearer_impl.h @@ -31,6 +31,7 @@ class f1u_bearer_impl final : public f1u_bearer, public f1u_rx_pdu_handler, publ f1u_rx_delivery_notifier& rx_delivery_notifier_, f1u_rx_sdu_notifier& rx_sdu_notifier_, timer_factory timers, + task_executor& ul_exec_, f1u_bearer_disconnector& diconnector_); f1u_bearer_impl(const f1u_bearer_impl&) = delete; f1u_bearer_impl& operator=(const f1u_bearer_impl&) = delete; @@ -62,6 +63,7 @@ class f1u_bearer_impl final : public f1u_bearer, public f1u_rx_pdu_handler, publ f1u_rx_sdu_notifier& rx_sdu_notifier; f1u_bearer_disconnector& disconnector; up_transport_layer_info ul_tnl_info; + task_executor& ul_exec; /// Downlink notification timer that triggers periodic transmission of discard blocks towards lower layers. The /// purpose of this timer is to avoid excessive downlink notifications for every PDCP SN that is discarded by upper @@ -71,6 +73,8 @@ class f1u_bearer_impl final : public f1u_bearer, public f1u_rx_pdu_handler, publ /// Collection of pending \c nru_pdcp_sn_discard_block objects. nru_pdcp_sn_discard_blocks discard_blocks; + void handle_pdu_impl(nru_ul_message msg); + /// \brief Fills the provided \c nru_dl_message with all SDU discard blocks that have been aggregated since the last /// call of this function (or since creation of this object). /// \param msg The message to be filled with SDU discard blocks. diff --git a/lib/f1u/local_connector/f1u_local_connector.cpp b/lib/f1u/local_connector/f1u_local_connector.cpp index 21182099cb..8e54984802 100644 --- a/lib/f1u/local_connector/f1u_local_connector.cpp +++ b/lib/f1u/local_connector/f1u_local_connector.cpp @@ -22,6 +22,7 @@ f1u_local_connector::create_cu_bearer(uint32_t ue_in const up_transport_layer_info& ul_up_tnl_info, srs_cu_up::f1u_rx_delivery_notifier& rx_delivery_notifier, srs_cu_up::f1u_rx_sdu_notifier& rx_sdu_notifier, + task_executor& ul_exec, timer_factory timers) { logger_cu.info("Creating CU F1-U bearer with UL GTP Tunnel={}", ul_up_tnl_info); @@ -32,7 +33,7 @@ f1u_local_connector::create_cu_bearer(uint32_t ue_in std::unique_ptr cu_tx = std::make_unique(ue_index, drb_id, ul_up_tnl_info); std::unique_ptr f1u_bearer = srs_cu_up::create_f1u_bearer( - ue_index, drb_id, ul_up_tnl_info, *cu_tx, rx_delivery_notifier, rx_sdu_notifier, timers, *this); + ue_index, drb_id, ul_up_tnl_info, *cu_tx, rx_delivery_notifier, rx_sdu_notifier, timers, ul_exec, *this); f1u_cu_bearer cu_bearer(std::move(cu_tx), f1u_bearer.get()); cu_map.insert({ul_up_tnl_info, std::move(cu_bearer)}); return f1u_bearer; diff --git a/tests/integrationtests/rlc/rlc_stress_test_args.h b/tests/integrationtests/rlc/rlc_stress_test_args.h index 586be4c65f..a79dc238b3 100644 --- a/tests/integrationtests/rlc/rlc_stress_test_args.h +++ b/tests/integrationtests/rlc/rlc_stress_test_args.h @@ -114,7 +114,7 @@ inline bool parse_args(stress_test_args& args, int argc, char* argv[]) " -d, --pdu_drop_rate Set rate at which RLC PDUs are dropped.\n" " -c, --pdu_cut_rate Set rate at which RLC PDUs are chopped in length.\n" " -D, --pdu_duplicate_rate Set rate at which RLC PDUs are dropped.\n" - " -l, --nof_ttis Set number of TTIs to emulate.\n" + " -t, --nof_ttis Set number of TTIs to emulate.\n" " -l, --log_filename Set log filename. Use 'stdout' to print to console.\n" " --pdcp_sn_size Set PDCP SN size.\n" " --pdcp_t_reordering Set PDCP t-Reordering timeout (ms).\n" diff --git a/tests/unittests/cu_up/cu_up_test_helpers.h b/tests/unittests/cu_up/cu_up_test_helpers.h index 6680aabfe1..db93afc8d9 100644 --- a/tests/unittests/cu_up/cu_up_test_helpers.h +++ b/tests/unittests/cu_up/cu_up_test_helpers.h @@ -238,6 +238,7 @@ class dummy_f1u_gateway final : public f1u_cu_up_gateway const up_transport_layer_info& ul_up_tnl_info, srs_cu_up::f1u_rx_delivery_notifier& cu_delivery, srs_cu_up::f1u_rx_sdu_notifier& cu_rx, + task_executor& ul_exec, timer_factory timers) override { created_ul_teid_list.push_back(ul_up_tnl_info.gtp_teid); diff --git a/tests/unittests/cu_up/pdu_session_manager_test.h b/tests/unittests/cu_up/pdu_session_manager_test.h index 6a66b1a613..413eeee4a3 100644 --- a/tests/unittests/cu_up/pdu_session_manager_test.h +++ b/tests/unittests/cu_up/pdu_session_manager_test.h @@ -55,6 +55,8 @@ class pdu_session_manager_test : public ::testing::Test *gtpu_tx_notifier, *gtpu_rx_demux, teid_worker, + teid_worker, + teid_worker, gtpu_pcap); } diff --git a/tests/unittests/f1u/common/f1u_connector_test.cpp b/tests/unittests/f1u/common/f1u_connector_test.cpp index 05b3771171..40a032671d 100644 --- a/tests/unittests/f1u/common/f1u_connector_test.cpp +++ b/tests/unittests/f1u/common/f1u_connector_test.cpp @@ -118,7 +118,7 @@ TEST_F(f1u_connector_test, attach_detach_cu_up_f1u_to_du_f1u) dummy_f1u_cu_up_rx_sdu_notifier cu_rx; dummy_f1u_cu_up_rx_delivery_notifier cu_delivery; std::unique_ptr cu_bearer = - cu_gw->create_cu_bearer(0, drb_id_t::drb1, ul_tnl, cu_delivery, cu_rx, timers); + cu_gw->create_cu_bearer(0, drb_id_t::drb1, ul_tnl, cu_delivery, cu_rx, ue_worker, timers); // Create DU TX notifier adapter and RX handler dummy_f1u_du_rx_sdu_notifier du_rx; @@ -168,7 +168,7 @@ TEST_F(f1u_connector_test, detach_du_f1u_first) dummy_f1u_cu_up_rx_sdu_notifier cu_rx; dummy_f1u_cu_up_rx_delivery_notifier cu_delivery; std::unique_ptr cu_bearer = - cu_gw->create_cu_bearer(0, drb_id_t::drb1, ul_tnl, cu_delivery, cu_rx, timers); + cu_gw->create_cu_bearer(0, drb_id_t::drb1, ul_tnl, cu_delivery, cu_rx, ue_worker, timers); // Create DU TX notifier adapter and RX handler dummy_f1u_du_rx_sdu_notifier du_rx; @@ -219,7 +219,7 @@ TEST_F(f1u_connector_test, update_du_f1u) dummy_f1u_cu_up_rx_sdu_notifier cu_rx; dummy_f1u_cu_up_rx_delivery_notifier cu_delivery; std::unique_ptr cu_bearer = - cu_gw->create_cu_bearer(0, drb_id_t::drb1, ul_tnl, cu_delivery, cu_rx, timers); + cu_gw->create_cu_bearer(0, drb_id_t::drb1, ul_tnl, cu_delivery, cu_rx, ue_worker, timers); // Create DU TX notifier adapter and RX handler dummy_f1u_du_rx_sdu_notifier du_rx1; diff --git a/tests/unittests/f1u/cu_up/f1u_cu_up_bearer_test.cpp b/tests/unittests/f1u/cu_up/f1u_cu_up_bearer_test.cpp index a9db15745f..7bcf5b12e4 100644 --- a/tests/unittests/f1u/cu_up/f1u_cu_up_bearer_test.cpp +++ b/tests/unittests/f1u/cu_up/f1u_cu_up_bearer_test.cpp @@ -91,6 +91,7 @@ class f1u_cu_up_test : public ::testing::Test, public f1u_trx_test *tester, *tester, timer_factory{timers, ue_worker}, + ue_worker, *tester); } From cadb50c0fa4163bd11cdb460fe06d232c7f59277 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Fri, 1 Mar 2024 09:54:49 +0000 Subject: [PATCH 051/140] pdcp: more fixes to logging when integrity fails --- include/srsran/security/security.h | 16 ++++++++++++++++ lib/pdcp/pdcp_entity_rx.cpp | 9 ++++----- lib/pdcp/pdcp_entity_tx.cpp | 6 +++--- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/include/srsran/security/security.h b/include/srsran/security/security.h index 7f301ad302..11f76ab731 100644 --- a/include/srsran/security/security.h +++ b/include/srsran/security/security.h @@ -450,4 +450,20 @@ struct formatter { return format_to(ctx.out(), "\n\t{:02x}", fmt::join(key.begin() + 16, key.end(), " ")); } }; + +template <> +struct formatter { + template + auto parse(ParseContext& ctx) -> decltype(ctx.begin()) + { + return ctx.begin(); + } + + template + auto format(const srsran::security::sec_mac& mac, FormatContext& ctx) -> decltype(std::declval().out()) + { + return format_to(ctx.out(), "\n\t{:02x}", fmt::join(mac, " ")); + } +}; + } // namespace fmt diff --git a/lib/pdcp/pdcp_entity_rx.cpp b/lib/pdcp/pdcp_entity_rx.cpp index 5900ab1d3a..5848615cb1 100644 --- a/lib/pdcp/pdcp_entity_rx.cpp +++ b/lib/pdcp/pdcp_entity_rx.cpp @@ -461,10 +461,9 @@ bool pdcp_entity_rx::integrity_verify(byte_buffer_view buf, uint32_t count, cons count, bearer_id, direction); - logger.log( - level, (uint8_t*)sec_cfg.k_128_int.value().data(), sec_cfg.k_128_int.value().size(), "Integrity check key."); - logger.log(level, (uint8_t*)mac_exp.data(), mac_exp.size(), "MAC expected."); - logger.log(level, (uint8_t*)mac.data(), mac.size(), "MAC found."); + logger.log(level, "Integrity check key: {}", sec_cfg.k_128_int); + logger.log(level, "MAC expected: {}", mac_exp); + logger.log(level, "MAC found: {}", mac); logger.log(level, buf.begin(), buf.end(), "Integrity check input message. len={}", buf.length()); } @@ -474,7 +473,7 @@ bool pdcp_entity_rx::integrity_verify(byte_buffer_view buf, uint32_t count, cons byte_buffer pdcp_entity_rx::cipher_decrypt(byte_buffer_view& msg, uint32_t count) { logger.log_debug("Cipher decrypt. count={} bearer_id={} dir={}", count, bearer_id, direction); - logger.log_debug((uint8_t*)sec_cfg.k_128_enc.data(), sec_cfg.k_128_enc.size(), "Cipher decrypt key."); + logger.log_debug("Cipher decrypt key: {}", sec_cfg.k_128_enc); logger.log_debug(msg.begin(), msg.end(), "Cipher decrypt input msg."); byte_buffer ct; diff --git a/lib/pdcp/pdcp_entity_tx.cpp b/lib/pdcp/pdcp_entity_tx.cpp index 091bea86fa..edae23b757 100644 --- a/lib/pdcp/pdcp_entity_tx.cpp +++ b/lib/pdcp/pdcp_entity_tx.cpp @@ -321,15 +321,15 @@ void pdcp_entity_tx::integrity_generate(security::sec_mac& mac, byte_buffer_view } logger.log_debug("Integrity gen. count={} bearer_id={} dir={}", count, bearer_id, direction); - logger.log_debug((uint8_t*)sec_cfg.k_128_int.value().data(), sec_cfg.k_128_int.value().size(), "Integrity gen key."); + logger.log_debug("Integrity gen key: {}", sec_cfg.k_128_int); logger.log_debug(buf.begin(), buf.end(), "Integrity gen input message."); - logger.log_debug((uint8_t*)mac.data(), mac.size(), "MAC generated."); + logger.log_debug("MAC generated: {}", mac); } void pdcp_entity_tx::cipher_encrypt(byte_buffer_view& buf, uint32_t count) { logger.log_debug("Cipher encrypt. count={} bearer_id={} dir={}", count, bearer_id, direction); - logger.log_debug((uint8_t*)sec_cfg.k_128_enc.data(), sec_cfg.k_128_enc.size(), "Cipher encrypt key."); + logger.log_debug("Cipher encrypt key: {}", sec_cfg.k_128_enc); logger.log_debug(buf.begin(), buf.end(), "Cipher encrypt input msg."); switch (sec_cfg.cipher_algo) { From 781d094c42cfa379df9ebc060684f6761b693ce3 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Thu, 29 Feb 2024 14:24:16 +0100 Subject: [PATCH 052/140] f1u,cu_up: add UE inactivity timer --- include/srsran/f1u/cu_up/f1u_bearer_factory.h | 1 + include/srsran/f1u/cu_up/f1u_gateway.h | 3 ++- .../f1u/local_connector/f1u_local_connector.h | 3 ++- lib/cu_up/pdu_session_manager_impl.cpp | 6 ++++-- lib/f1u/cu_up/f1u_bearer_factory.cpp | 2 ++ lib/f1u/cu_up/f1u_bearer_impl.cpp | 6 +++++- lib/f1u/cu_up/f1u_bearer_impl.h | 5 +++++ lib/f1u/local_connector/f1u_local_connector.cpp | 17 +++++++++++++---- tests/unittests/cu_up/cu_up_test_helpers.h | 3 ++- .../unittests/f1u/common/f1u_connector_test.cpp | 9 ++++++--- .../f1u/cu_up/f1u_cu_up_bearer_test.cpp | 17 +++++++++++------ 11 files changed, 53 insertions(+), 19 deletions(-) diff --git a/include/srsran/f1u/cu_up/f1u_bearer_factory.h b/include/srsran/f1u/cu_up/f1u_bearer_factory.h index c7a9f1d845..dc28e86670 100644 --- a/include/srsran/f1u/cu_up/f1u_bearer_factory.h +++ b/include/srsran/f1u/cu_up/f1u_bearer_factory.h @@ -29,6 +29,7 @@ std::unique_ptr create_f1u_bearer(uint32_t ue_ f1u_rx_delivery_notifier& rx_delivery_notifier, f1u_rx_sdu_notifier& rx_sdu_notifier, timer_factory timers, + unique_timer& ue_inactivity_timer, task_executor& ul_exec, f1u_bearer_disconnector& disconnector); diff --git a/include/srsran/f1u/cu_up/f1u_gateway.h b/include/srsran/f1u/cu_up/f1u_gateway.h index aad2103b27..39ca2ca1ba 100644 --- a/include/srsran/f1u/cu_up/f1u_gateway.h +++ b/include/srsran/f1u/cu_up/f1u_gateway.h @@ -38,7 +38,8 @@ class f1u_cu_up_gateway : public srs_cu_up::f1u_bearer_disconnector srs_cu_up::f1u_rx_delivery_notifier& rx_delivery_notifier, srs_cu_up::f1u_rx_sdu_notifier& rx_sdu_notifier, task_executor& ul_exec, - timer_factory timers) = 0; + timer_factory timers, + unique_timer& ue_inactivity_timer) = 0; virtual void attach_dl_teid(const up_transport_layer_info& ul_up_tnl_info, const up_transport_layer_info& dl_up_tnl_info) = 0; diff --git a/include/srsran/f1u/local_connector/f1u_local_connector.h b/include/srsran/f1u/local_connector/f1u_local_connector.h index 4fdb8a1704..6ac4f28ebe 100644 --- a/include/srsran/f1u/local_connector/f1u_local_connector.h +++ b/include/srsran/f1u/local_connector/f1u_local_connector.h @@ -66,7 +66,8 @@ class f1u_local_connector final : public srs_du::f1u_du_gateway, public f1u_cu_u srs_cu_up::f1u_rx_delivery_notifier& rx_delivery_notifier, srs_cu_up::f1u_rx_sdu_notifier& rx_sdu_notifier, task_executor& ul_exec, - timer_factory timers) override; + timer_factory timers, + unique_timer& ue_inactivity_timer) override; void attach_dl_teid(const up_transport_layer_info& ul_up_tnl_info, const up_transport_layer_info& dl_up_tnl_info) override; diff --git a/lib/cu_up/pdu_session_manager_impl.cpp b/lib/cu_up/pdu_session_manager_impl.cpp index 78dda7faf3..586ef7de1a 100644 --- a/lib/cu_up/pdu_session_manager_impl.cpp +++ b/lib/cu_up/pdu_session_manager_impl.cpp @@ -192,7 +192,8 @@ drb_setup_result pdu_session_manager_impl::handle_drb_to_setup_item(pdu_session& new_drb->f1u_to_pdcp_adapter, new_drb->f1u_to_pdcp_adapter, ue_ul_exec, - timers); + timers, + ue_inactivity_timer); new_drb->f1u_ul_teid = f1u_ul_teid; drb_result.gtp_tunnel = f1u_ul_tunnel_addr; @@ -379,7 +380,8 @@ pdu_session_manager_impl::modify_pdu_session(const e1ap_pdu_session_res_to_modif drb->f1u_to_pdcp_adapter, drb->f1u_to_pdcp_adapter, ue_dl_exec, - timers); + timers, + ue_inactivity_timer); drb_iter->second->pdcp_to_f1u_adapter.disconnect_f1u(); drb_result.gtp_tunnel = f1u_ul_tunnel_addr; diff --git a/lib/f1u/cu_up/f1u_bearer_factory.cpp b/lib/f1u/cu_up/f1u_bearer_factory.cpp index a58c0f3a1b..b72baf8f29 100644 --- a/lib/f1u/cu_up/f1u_bearer_factory.cpp +++ b/lib/f1u/cu_up/f1u_bearer_factory.cpp @@ -22,6 +22,7 @@ std::unique_ptr srsran::srs_cu_up::create_f1u_bearer(uint32_t f1u_rx_delivery_notifier& rx_delivery_notifier, f1u_rx_sdu_notifier& rx_sdu_notifier, timer_factory timers, + unique_timer& ue_inactivity_timer, task_executor& ul_exec, f1u_bearer_disconnector& disconnector) { @@ -32,6 +33,7 @@ std::unique_ptr srsran::srs_cu_up::create_f1u_bearer(uint32_t rx_delivery_notifier, rx_sdu_notifier, timers, + ue_inactivity_timer, ul_exec, disconnector); return bearer; diff --git a/lib/f1u/cu_up/f1u_bearer_impl.cpp b/lib/f1u/cu_up/f1u_bearer_impl.cpp index 1c1984d548..3b251db378 100644 --- a/lib/f1u/cu_up/f1u_bearer_impl.cpp +++ b/lib/f1u/cu_up/f1u_bearer_impl.cpp @@ -21,6 +21,7 @@ f1u_bearer_impl::f1u_bearer_impl(uint32_t ue_index, f1u_rx_delivery_notifier& rx_delivery_notifier_, f1u_rx_sdu_notifier& rx_sdu_notifier_, timer_factory timers, + unique_timer& ue_inactivity_timer_, task_executor& ul_exec_, f1u_bearer_disconnector& disconnector_) : logger("CU-F1-U", {ue_index, drb_id_, ul_tnl_info_}), @@ -30,7 +31,8 @@ f1u_bearer_impl::f1u_bearer_impl(uint32_t ue_index, disconnector(disconnector_), ul_tnl_info(ul_tnl_info_), ul_exec(ul_exec_), - dl_notif_timer(timers.create_timer()) + dl_notif_timer(timers.create_timer()), + ue_inactivity_timer(ue_inactivity_timer_) { dl_notif_timer.set(std::chrono::milliseconds(f1u_dl_notif_time_ms), [this](timer_id_t tid) { on_expired_dl_notif_timer(); }); @@ -50,6 +52,7 @@ void f1u_bearer_impl::handle_pdu_impl(nru_ul_message msg) logger.log_debug("F1-U bearer received PDU"); // handle T-PDU if (!msg.t_pdu.empty()) { + ue_inactivity_timer.run(); // restart inactivity timer due to UL PDU logger.log_debug("Delivering T-PDU of size={}", msg.t_pdu.length()); rx_sdu_notifier.on_new_sdu(std::move(msg.t_pdu)); } @@ -58,6 +61,7 @@ void f1u_bearer_impl::handle_pdu_impl(nru_ul_message msg) nru_dl_data_delivery_status& status = msg.data_delivery_status.value(); // Highest transmitted PDCP SN if (status.highest_transmitted_pdcp_sn.has_value()) { + ue_inactivity_timer.run(); // restart inactivity timer due to confirmed transmission of DL PDU uint32_t pdcp_sn = status.highest_transmitted_pdcp_sn.value(); logger.log_debug("Notifying highest transmitted pdcp_sn={}", pdcp_sn); rx_delivery_notifier.on_transmit_notification(pdcp_sn); diff --git a/lib/f1u/cu_up/f1u_bearer_impl.h b/lib/f1u/cu_up/f1u_bearer_impl.h index e2a4c79e20..02edc30479 100644 --- a/lib/f1u/cu_up/f1u_bearer_impl.h +++ b/lib/f1u/cu_up/f1u_bearer_impl.h @@ -31,6 +31,7 @@ class f1u_bearer_impl final : public f1u_bearer, public f1u_rx_pdu_handler, publ f1u_rx_delivery_notifier& rx_delivery_notifier_, f1u_rx_sdu_notifier& rx_sdu_notifier_, timer_factory timers, + unique_timer& ue_inactivity_timer_, task_executor& ul_exec_, f1u_bearer_disconnector& diconnector_); f1u_bearer_impl(const f1u_bearer_impl&) = delete; @@ -70,6 +71,10 @@ class f1u_bearer_impl final : public f1u_bearer, public f1u_rx_pdu_handler, publ /// layers. unique_timer dl_notif_timer; + /// UE inactivity timer that is injected from parent entities. The timer must run in the UL executor! + /// The timer shall be restarted on each UL PDU (= UL activity) and on each transmit notification (= DL activity). + unique_timer& ue_inactivity_timer; + /// Collection of pending \c nru_pdcp_sn_discard_block objects. nru_pdcp_sn_discard_blocks discard_blocks; diff --git a/lib/f1u/local_connector/f1u_local_connector.cpp b/lib/f1u/local_connector/f1u_local_connector.cpp index 8e54984802..28eb3ce526 100644 --- a/lib/f1u/local_connector/f1u_local_connector.cpp +++ b/lib/f1u/local_connector/f1u_local_connector.cpp @@ -23,7 +23,8 @@ f1u_local_connector::create_cu_bearer(uint32_t ue_in srs_cu_up::f1u_rx_delivery_notifier& rx_delivery_notifier, srs_cu_up::f1u_rx_sdu_notifier& rx_sdu_notifier, task_executor& ul_exec, - timer_factory timers) + timer_factory timers, + unique_timer& ue_inactivity_timer) { logger_cu.info("Creating CU F1-U bearer with UL GTP Tunnel={}", ul_up_tnl_info); std::unique_lock lock(map_mutex); @@ -32,9 +33,17 @@ f1u_local_connector::create_cu_bearer(uint32_t ue_in ul_up_tnl_info); std::unique_ptr cu_tx = std::make_unique(ue_index, drb_id, ul_up_tnl_info); - std::unique_ptr f1u_bearer = srs_cu_up::create_f1u_bearer( - ue_index, drb_id, ul_up_tnl_info, *cu_tx, rx_delivery_notifier, rx_sdu_notifier, timers, ul_exec, *this); - f1u_cu_bearer cu_bearer(std::move(cu_tx), f1u_bearer.get()); + std::unique_ptr f1u_bearer = srs_cu_up::create_f1u_bearer(ue_index, + drb_id, + ul_up_tnl_info, + *cu_tx, + rx_delivery_notifier, + rx_sdu_notifier, + timers, + ue_inactivity_timer, + ul_exec, + *this); + f1u_cu_bearer cu_bearer(std::move(cu_tx), f1u_bearer.get()); cu_map.insert({ul_up_tnl_info, std::move(cu_bearer)}); return f1u_bearer; } diff --git a/tests/unittests/cu_up/cu_up_test_helpers.h b/tests/unittests/cu_up/cu_up_test_helpers.h index db93afc8d9..3d53c7b879 100644 --- a/tests/unittests/cu_up/cu_up_test_helpers.h +++ b/tests/unittests/cu_up/cu_up_test_helpers.h @@ -239,7 +239,8 @@ class dummy_f1u_gateway final : public f1u_cu_up_gateway srs_cu_up::f1u_rx_delivery_notifier& cu_delivery, srs_cu_up::f1u_rx_sdu_notifier& cu_rx, task_executor& ul_exec, - timer_factory timers) override + timer_factory timers, + unique_timer& ue_inactivity_timer) override { created_ul_teid_list.push_back(ul_up_tnl_info.gtp_teid); bearer.connect_f1u_rx_sdu_notifier(cu_rx); diff --git a/tests/unittests/f1u/common/f1u_connector_test.cpp b/tests/unittests/f1u/common/f1u_connector_test.cpp index 40a032671d..44e6e525b3 100644 --- a/tests/unittests/f1u/common/f1u_connector_test.cpp +++ b/tests/unittests/f1u/common/f1u_connector_test.cpp @@ -76,6 +76,8 @@ class f1u_connector_test : public ::testing::Test timers = timer_factory{timer_mng, ue_worker}; + ue_inactivity_timer = timers.create_timer(); + // set F1-U bearer config config.t_notify = 10; } @@ -89,6 +91,7 @@ class f1u_connector_test : public ::testing::Test timer_manager timer_mng; manual_task_worker ue_worker{128}; timer_factory timers; + unique_timer ue_inactivity_timer; srs_du::f1u_config config; std::unique_ptr f1u_conn; @@ -118,7 +121,7 @@ TEST_F(f1u_connector_test, attach_detach_cu_up_f1u_to_du_f1u) dummy_f1u_cu_up_rx_sdu_notifier cu_rx; dummy_f1u_cu_up_rx_delivery_notifier cu_delivery; std::unique_ptr cu_bearer = - cu_gw->create_cu_bearer(0, drb_id_t::drb1, ul_tnl, cu_delivery, cu_rx, ue_worker, timers); + cu_gw->create_cu_bearer(0, drb_id_t::drb1, ul_tnl, cu_delivery, cu_rx, ue_worker, timers, ue_inactivity_timer); // Create DU TX notifier adapter and RX handler dummy_f1u_du_rx_sdu_notifier du_rx; @@ -168,7 +171,7 @@ TEST_F(f1u_connector_test, detach_du_f1u_first) dummy_f1u_cu_up_rx_sdu_notifier cu_rx; dummy_f1u_cu_up_rx_delivery_notifier cu_delivery; std::unique_ptr cu_bearer = - cu_gw->create_cu_bearer(0, drb_id_t::drb1, ul_tnl, cu_delivery, cu_rx, ue_worker, timers); + cu_gw->create_cu_bearer(0, drb_id_t::drb1, ul_tnl, cu_delivery, cu_rx, ue_worker, timers, ue_inactivity_timer); // Create DU TX notifier adapter and RX handler dummy_f1u_du_rx_sdu_notifier du_rx; @@ -219,7 +222,7 @@ TEST_F(f1u_connector_test, update_du_f1u) dummy_f1u_cu_up_rx_sdu_notifier cu_rx; dummy_f1u_cu_up_rx_delivery_notifier cu_delivery; std::unique_ptr cu_bearer = - cu_gw->create_cu_bearer(0, drb_id_t::drb1, ul_tnl, cu_delivery, cu_rx, ue_worker, timers); + cu_gw->create_cu_bearer(0, drb_id_t::drb1, ul_tnl, cu_delivery, cu_rx, ue_worker, timers, ue_inactivity_timer); // Create DU TX notifier adapter and RX handler dummy_f1u_du_rx_sdu_notifier du_rx1; diff --git a/tests/unittests/f1u/cu_up/f1u_cu_up_bearer_test.cpp b/tests/unittests/f1u/cu_up/f1u_cu_up_bearer_test.cpp index 7bcf5b12e4..4b015adc79 100644 --- a/tests/unittests/f1u/cu_up/f1u_cu_up_bearer_test.cpp +++ b/tests/unittests/f1u/cu_up/f1u_cu_up_bearer_test.cpp @@ -82,15 +82,18 @@ class f1u_cu_up_test : public ::testing::Test, public f1u_trx_test // create tester and testee logger.info("Creating F1-U bearer"); - tester = std::make_unique(); - drb_id_t drb_id = drb_id_t::drb1; - f1u = std::make_unique(0, + tester = std::make_unique(); + drb_id_t drb_id = drb_id_t::drb1; + ue_inactivity_timer = ue_timer_factory.create_timer(); + ue_inactivity_timer.set(std::chrono::milliseconds(10000), [](timer_id_t) {}); + f1u = std::make_unique(0, drb_id, up_transport_layer_info{{"127.0.0.1"}, gtpu_teid_t{ul_teid_next.value()++}}, *tester, *tester, *tester, - timer_factory{timers, ue_worker}, + ue_timer_factory, + ue_inactivity_timer, ue_worker, *tester); } @@ -103,13 +106,15 @@ class f1u_cu_up_test : public ::testing::Test, public f1u_trx_test void tick() { - timers.tick(); + ue_timer_manager.tick(); ue_worker.run_pending_tasks(); } srslog::basic_logger& logger = srslog::fetch_basic_logger("TEST", false); - timer_manager timers; manual_task_worker ue_worker{128}; + timer_manager ue_timer_manager; + timer_factory ue_timer_factory{ue_timer_manager, ue_worker}; + unique_timer ue_inactivity_timer; std::unique_ptr tester; std::unique_ptr f1u; gtpu_teid_t ul_teid_next{1234}; From 8011b72f111c6005077114d1a5c59544859e90be Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Thu, 29 Feb 2024 14:31:59 +0100 Subject: [PATCH 053/140] sdap: remove UE inactivity timer --- include/srsran/sdap/sdap_factory.h | 1 - lib/cu_up/pdu_session_manager_impl.cpp | 5 ++--- lib/sdap/sdap_entity_impl.h | 16 ++++------------ lib/sdap/sdap_entity_rx_impl.h | 10 +--------- lib/sdap/sdap_entity_tx_impl.h | 10 +--------- lib/sdap/sdap_factory.cpp | 3 +-- tests/unittests/sdap/sdap_rx_test.cpp | 10 +--------- tests/unittests/sdap/sdap_test.h | 9 +-------- tests/unittests/sdap/sdap_tx_test.cpp | 10 +--------- 9 files changed, 12 insertions(+), 62 deletions(-) diff --git a/include/srsran/sdap/sdap_factory.h b/include/srsran/sdap/sdap_factory.h index a6f5baa3e1..d3ef166d9c 100644 --- a/include/srsran/sdap/sdap_factory.h +++ b/include/srsran/sdap/sdap_factory.h @@ -25,7 +25,6 @@ namespace srs_cu_up { struct sdap_entity_creation_message { uint32_t ue_index; pdu_session_id_t pdu_session_id; - unique_timer& ue_inactivity_timer; sdap_rx_sdu_notifier* rx_sdu_notifier; }; diff --git a/lib/cu_up/pdu_session_manager_impl.cpp b/lib/cu_up/pdu_session_manager_impl.cpp index 586ef7de1a..bbf52ec0a3 100644 --- a/lib/cu_up/pdu_session_manager_impl.cpp +++ b/lib/cu_up/pdu_session_manager_impl.cpp @@ -251,9 +251,8 @@ pdu_session_setup_result pdu_session_manager_impl::setup_pdu_session(const e1ap_ pdu_session_result.gtp_tunnel = n3_dl_tunnel_addr; // Create SDAP entity - sdap_entity_creation_message sdap_msg = { - ue_index, session.pdu_session_id, ue_inactivity_timer, &new_session->sdap_to_gtpu_adapter}; - new_session->sdap = create_sdap(sdap_msg); + sdap_entity_creation_message sdap_msg = {ue_index, session.pdu_session_id, &new_session->sdap_to_gtpu_adapter}; + new_session->sdap = create_sdap(sdap_msg); // Create GTPU entity gtpu_tunnel_ngu_creation_message msg = {}; diff --git a/lib/sdap/sdap_entity_impl.h b/lib/sdap/sdap_entity_impl.h index b31ebfff68..32fe5ee609 100644 --- a/lib/sdap/sdap_entity_impl.h +++ b/lib/sdap/sdap_entity_impl.h @@ -24,15 +24,8 @@ namespace srs_cu_up { class sdap_entity_impl : public sdap_entity, public sdap_tx_sdu_handler { public: - sdap_entity_impl(uint32_t ue_index_, - pdu_session_id_t psi_, - unique_timer& ue_inactivity_timer_, - sdap_rx_sdu_notifier& rx_sdu_notifier_) : - logger("SDAP", {ue_index_, psi_}), - ue_index(ue_index_), - psi(psi_), - ue_inactivity_timer(ue_inactivity_timer_), - rx_sdu_notifier(rx_sdu_notifier_) + sdap_entity_impl(uint32_t ue_index_, pdu_session_id_t psi_, sdap_rx_sdu_notifier& rx_sdu_notifier_) : + logger("SDAP", {ue_index_, psi_}), ue_index(ue_index_), psi(psi_), rx_sdu_notifier(rx_sdu_notifier_) { } ~sdap_entity_impl() override = default; @@ -74,12 +67,12 @@ class sdap_entity_impl : public sdap_entity, public sdap_tx_sdu_handler // create TX mapping std::unique_ptr tx = - std::make_unique(ue_index, psi, qfi, drb_id, ue_inactivity_timer, tx_pdu_notifier); + std::make_unique(ue_index, psi, qfi, drb_id, tx_pdu_notifier); tx_map.insert({qfi, std::move(tx)}); // create RX mapping std::unique_ptr rx = - std::make_unique(ue_index, psi, qfi, drb_id, ue_inactivity_timer, rx_sdu_notifier); + std::make_unique(ue_index, psi, qfi, drb_id, rx_sdu_notifier); rx_map.insert({drb_id, std::move(rx)}); } @@ -104,7 +97,6 @@ class sdap_entity_impl : public sdap_entity, public sdap_tx_sdu_handler sdap_session_logger logger; uint32_t ue_index; pdu_session_id_t psi; - unique_timer& ue_inactivity_timer; sdap_rx_sdu_notifier& rx_sdu_notifier; std::unordered_map> tx_map; diff --git a/lib/sdap/sdap_entity_rx_impl.h b/lib/sdap/sdap_entity_rx_impl.h index dc5efb8995..daaf34b844 100644 --- a/lib/sdap/sdap_entity_rx_impl.h +++ b/lib/sdap/sdap_entity_rx_impl.h @@ -12,7 +12,6 @@ #include "sdap_session_logger.h" #include "srsran/sdap/sdap.h" -#include "srsran/support/timers.h" namespace srsran { @@ -25,13 +24,8 @@ class sdap_entity_rx_impl : public sdap_rx_pdu_handler pdu_session_id_t psi, qos_flow_id_t qfi_, drb_id_t drb_id_, - unique_timer& ue_inactivity_timer_, sdap_rx_sdu_notifier& sdu_notifier_) : - logger("SDAP", {ue_index, psi, qfi_, drb_id_, "UL"}), - qfi(qfi_), - drb_id(drb_id_), - ue_inactivity_timer(ue_inactivity_timer_), - sdu_notifier(sdu_notifier_) + logger("SDAP", {ue_index, psi, qfi_, drb_id_, "UL"}), qfi(qfi_), drb_id(drb_id_), sdu_notifier(sdu_notifier_) { } @@ -40,7 +34,6 @@ class sdap_entity_rx_impl : public sdap_rx_pdu_handler // pass through with qfi logger.log_debug("RX SDU. {} sdu_len={}", qfi, pdu.length()); sdu_notifier.on_new_sdu(std::move(pdu), qfi); - ue_inactivity_timer.run(); } drb_id_t get_drb_id() const { return drb_id; } @@ -49,7 +42,6 @@ class sdap_entity_rx_impl : public sdap_rx_pdu_handler sdap_session_trx_logger logger; qos_flow_id_t qfi; drb_id_t drb_id; - unique_timer& ue_inactivity_timer; sdap_rx_sdu_notifier& sdu_notifier; }; diff --git a/lib/sdap/sdap_entity_tx_impl.h b/lib/sdap/sdap_entity_tx_impl.h index 6adc3937ad..8d6ca17eb5 100644 --- a/lib/sdap/sdap_entity_tx_impl.h +++ b/lib/sdap/sdap_entity_tx_impl.h @@ -12,7 +12,6 @@ #include "sdap_session_logger.h" #include "srsran/sdap/sdap.h" -#include "srsran/support/timers.h" namespace srsran { @@ -25,13 +24,8 @@ class sdap_entity_tx_impl pdu_session_id_t psi, qos_flow_id_t qfi_, drb_id_t drb_id_, - unique_timer& ue_inactivity_timer_, sdap_tx_pdu_notifier& pdu_notifier_) : - logger("SDAP", {ue_index, psi, qfi_, drb_id_, "DL"}), - qfi(qfi_), - drb_id(drb_id_), - ue_inactivity_timer(ue_inactivity_timer_), - pdu_notifier(pdu_notifier_) + logger("SDAP", {ue_index, psi, qfi_, drb_id_, "DL"}), qfi(qfi_), drb_id(drb_id_), pdu_notifier(pdu_notifier_) { } @@ -40,7 +34,6 @@ class sdap_entity_tx_impl // pass through logger.log_debug("TX PDU. {} pdu_len={}", qfi, sdu.length()); pdu_notifier.on_new_pdu(std::move(sdu)); - ue_inactivity_timer.run(); } drb_id_t get_drb_id() const { return drb_id; } @@ -49,7 +42,6 @@ class sdap_entity_tx_impl sdap_session_trx_logger logger; qos_flow_id_t qfi; drb_id_t drb_id; - unique_timer& ue_inactivity_timer; sdap_tx_pdu_notifier& pdu_notifier; }; diff --git a/lib/sdap/sdap_factory.cpp b/lib/sdap/sdap_factory.cpp index 7e144582a4..0061fba238 100644 --- a/lib/sdap/sdap_factory.cpp +++ b/lib/sdap/sdap_factory.cpp @@ -22,6 +22,5 @@ using namespace srs_cu_up; std::unique_ptr srsran::srs_cu_up::create_sdap(sdap_entity_creation_message& msg) { - return std::make_unique( - msg.ue_index, msg.pdu_session_id, msg.ue_inactivity_timer, *msg.rx_sdu_notifier); + return std::make_unique(msg.ue_index, msg.pdu_session_id, *msg.rx_sdu_notifier); } diff --git a/tests/unittests/sdap/sdap_rx_test.cpp b/tests/unittests/sdap/sdap_rx_test.cpp index 002c90c730..3fd514258b 100644 --- a/tests/unittests/sdap/sdap_rx_test.cpp +++ b/tests/unittests/sdap/sdap_rx_test.cpp @@ -10,7 +10,6 @@ #include "lib/sdap/sdap_entity_rx_impl.h" #include "srsran/sdap/sdap.h" -#include "srsran/support/executors/manual_task_worker.h" #include #include @@ -47,10 +46,7 @@ class sdap_rx_test : public ::testing::Test tester = std::make_unique(); // Create SDAP RX entity - ue_inactivity_timer = timers.create_timer(); - ue_inactivity_timer.set(std::chrono::milliseconds(10000), [](timer_id_t) {}); - sdap = std::make_unique( - 7, pdu_session_id_t::min, qos_flow_id_t::min, drb_id_t::drb1, ue_inactivity_timer, *tester); + sdap = std::make_unique(7, pdu_session_id_t::min, qos_flow_id_t::min, drb_id_t::drb1, *tester); } void TearDown() override @@ -60,10 +56,6 @@ class sdap_rx_test : public ::testing::Test } srslog::basic_logger& logger = srslog::fetch_basic_logger("TEST", false); - manual_task_worker worker{64}; - timer_manager timers_manager; - timer_factory timers{timers_manager, worker}; - unique_timer ue_inactivity_timer; std::unique_ptr tester; std::unique_ptr sdap; }; diff --git a/tests/unittests/sdap/sdap_test.h b/tests/unittests/sdap/sdap_test.h index 3c44a2232a..c76532350f 100644 --- a/tests/unittests/sdap/sdap_test.h +++ b/tests/unittests/sdap/sdap_test.h @@ -10,7 +10,6 @@ #include "lib/sdap/sdap_entity_impl.h" #include "srsran/sdap/sdap.h" -#include "srsran/support/executors/manual_task_worker.h" #include #include @@ -62,9 +61,7 @@ class sdap_test : public ::testing::Test dl_sink2 = std::make_unique(); // Create SDAP TX entity - ue_inactivity_timer = timers.create_timer(); - ue_inactivity_timer.set(std::chrono::milliseconds(10000), [](timer_id_t) {}); - sdap = std::make_unique(7, pdu_session_id_t::min, ue_inactivity_timer, *ul_sink); + sdap = std::make_unique(7, pdu_session_id_t::min, *ul_sink); } void TearDown() override @@ -74,10 +71,6 @@ class sdap_test : public ::testing::Test } srslog::basic_logger& logger = srslog::fetch_basic_logger("TEST", false); - manual_task_worker worker{64}; - timer_manager timers_manager; - timer_factory timers{timers_manager, worker}; - unique_timer ue_inactivity_timer; std::unique_ptr ul_sink; std::unique_ptr dl_sink1; std::unique_ptr dl_sink2; diff --git a/tests/unittests/sdap/sdap_tx_test.cpp b/tests/unittests/sdap/sdap_tx_test.cpp index 59ec08a2fa..d5c55456a9 100644 --- a/tests/unittests/sdap/sdap_tx_test.cpp +++ b/tests/unittests/sdap/sdap_tx_test.cpp @@ -10,7 +10,6 @@ #include "lib/sdap/sdap_entity_tx_impl.h" #include "srsran/sdap/sdap.h" -#include "srsran/support/executors/manual_task_worker.h" #include #include @@ -47,10 +46,7 @@ class sdap_tx_test : public ::testing::Test tester = std::make_unique(); // Create SDAP TX entity - ue_inactivity_timer = timers.create_timer(); - ue_inactivity_timer.set(std::chrono::milliseconds(10000), [](timer_id_t) {}); - sdap = std::make_unique( - 7, pdu_session_id_t::min, qos_flow_id_t::min, drb_id_t::drb1, ue_inactivity_timer, *tester); + sdap = std::make_unique(7, pdu_session_id_t::min, qos_flow_id_t::min, drb_id_t::drb1, *tester); } void TearDown() override @@ -60,10 +56,6 @@ class sdap_tx_test : public ::testing::Test } srslog::basic_logger& logger = srslog::fetch_basic_logger("TEST", false); - manual_task_worker worker{64}; - timer_manager timers_manager; - timer_factory timers{timers_manager, worker}; - unique_timer ue_inactivity_timer; std::unique_ptr tester; std::unique_ptr sdap; }; From aaeb7bbc27bf4378ea07852ed3277cb0e52bf5ee Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Thu, 29 Feb 2024 15:08:05 +0100 Subject: [PATCH 054/140] cu_up,cu_cp: inject all executor-specific timer factories This also extends timer factory names with the name of the executor that is intended to be associated with it. --- include/srsran/f1u/cu_up/f1u_bearer_factory.h | 2 +- include/srsran/f1u/cu_up/f1u_gateway.h | 2 +- .../f1u/local_connector/f1u_local_connector.h | 2 +- include/srsran/gtpu/gtpu_tunnel_ngu_factory.h | 2 +- include/srsran/pdcp/pdcp_factory.h | 4 +- lib/cu_up/pdu_session_manager_impl.cpp | 18 ++++++--- lib/cu_up/pdu_session_manager_impl.h | 10 +++-- lib/cu_up/ue_context.h | 38 ++++++++++++++----- lib/cu_up/ue_manager.cpp | 9 ++++- lib/f1u/cu_up/f1u_bearer_factory.cpp | 4 +- lib/f1u/cu_up/f1u_bearer_impl.cpp | 4 +- lib/f1u/cu_up/f1u_bearer_impl.h | 2 +- .../local_connector/f1u_local_connector.cpp | 4 +- lib/gtpu/gtpu_tunnel_impl_ngu.h | 4 +- lib/gtpu/gtpu_tunnel_ngu_factory.cpp | 2 +- lib/gtpu/gtpu_tunnel_ngu_rx.h | 10 ++--- lib/gtpu/gtpu_tunnel_ngu_tx.h | 2 +- lib/pdcp/pdcp_entity_impl.h | 12 ++++-- lib/pdcp/pdcp_entity_rx.cpp | 6 +-- lib/pdcp/pdcp_entity_rx.h | 4 +- lib/pdcp/pdcp_entity_tx.cpp | 2 +- lib/pdcp/pdcp_entity_tx.h | 6 +-- lib/pdcp/pdcp_factory.cpp | 4 +- lib/rrc/ue/rrc_ue_srb_context.h | 5 ++- .../integrationtests/rlc/rlc_stress_test.cpp | 4 +- tests/unittests/cu_up/cu_up_test_helpers.h | 2 +- .../cu_up/pdu_session_manager_test.h | 2 + tests/unittests/gtpu/gtpu_tunnel_ngu_test.cpp | 6 +-- 28 files changed, 111 insertions(+), 61 deletions(-) diff --git a/include/srsran/f1u/cu_up/f1u_bearer_factory.h b/include/srsran/f1u/cu_up/f1u_bearer_factory.h index dc28e86670..ec803ff4db 100644 --- a/include/srsran/f1u/cu_up/f1u_bearer_factory.h +++ b/include/srsran/f1u/cu_up/f1u_bearer_factory.h @@ -28,7 +28,7 @@ std::unique_ptr create_f1u_bearer(uint32_t ue_ f1u_tx_pdu_notifier& tx_pdu_notifier, f1u_rx_delivery_notifier& rx_delivery_notifier, f1u_rx_sdu_notifier& rx_sdu_notifier, - timer_factory timers, + timer_factory ue_dl_timer_factory, unique_timer& ue_inactivity_timer, task_executor& ul_exec, f1u_bearer_disconnector& disconnector); diff --git a/include/srsran/f1u/cu_up/f1u_gateway.h b/include/srsran/f1u/cu_up/f1u_gateway.h index 39ca2ca1ba..e6b83c3560 100644 --- a/include/srsran/f1u/cu_up/f1u_gateway.h +++ b/include/srsran/f1u/cu_up/f1u_gateway.h @@ -38,7 +38,7 @@ class f1u_cu_up_gateway : public srs_cu_up::f1u_bearer_disconnector srs_cu_up::f1u_rx_delivery_notifier& rx_delivery_notifier, srs_cu_up::f1u_rx_sdu_notifier& rx_sdu_notifier, task_executor& ul_exec, - timer_factory timers, + timer_factory ue_dl_timer_factory, unique_timer& ue_inactivity_timer) = 0; virtual void attach_dl_teid(const up_transport_layer_info& ul_up_tnl_info, diff --git a/include/srsran/f1u/local_connector/f1u_local_connector.h b/include/srsran/f1u/local_connector/f1u_local_connector.h index 6ac4f28ebe..fc7ff95261 100644 --- a/include/srsran/f1u/local_connector/f1u_local_connector.h +++ b/include/srsran/f1u/local_connector/f1u_local_connector.h @@ -66,7 +66,7 @@ class f1u_local_connector final : public srs_du::f1u_du_gateway, public f1u_cu_u srs_cu_up::f1u_rx_delivery_notifier& rx_delivery_notifier, srs_cu_up::f1u_rx_sdu_notifier& rx_sdu_notifier, task_executor& ul_exec, - timer_factory timers, + timer_factory ue_dl_timer_factory, unique_timer& ue_inactivity_timer) override; void attach_dl_teid(const up_transport_layer_info& ul_up_tnl_info, diff --git a/include/srsran/gtpu/gtpu_tunnel_ngu_factory.h b/include/srsran/gtpu/gtpu_tunnel_ngu_factory.h index f4e4e4fd7b..275d21bb8d 100644 --- a/include/srsran/gtpu/gtpu_tunnel_ngu_factory.h +++ b/include/srsran/gtpu/gtpu_tunnel_ngu_factory.h @@ -27,7 +27,7 @@ struct gtpu_tunnel_ngu_creation_message { dlt_pcap* gtpu_pcap; gtpu_tunnel_ngu_rx_lower_layer_notifier* rx_lower; gtpu_tunnel_tx_upper_layer_notifier* tx_upper; - timer_factory timers; + timer_factory ue_dl_timer_factory; }; /// Creates an instance of a GTP-U entity. diff --git a/include/srsran/pdcp/pdcp_factory.h b/include/srsran/pdcp/pdcp_factory.h index cf71e85a8a..8f796db4fc 100644 --- a/include/srsran/pdcp/pdcp_factory.h +++ b/include/srsran/pdcp/pdcp_factory.h @@ -32,7 +32,9 @@ struct pdcp_entity_creation_message { pdcp_tx_upper_control_notifier* tx_upper_cn; pdcp_rx_upper_data_notifier* rx_upper_dn; pdcp_rx_upper_control_notifier* rx_upper_cn; - timer_factory timers; + timer_factory ue_dl_timer_factory; + timer_factory ue_ul_timer_factory; + timer_factory ue_ctrl_timer_factory; }; /// Creates an instance of a PDCP entity. diff --git a/lib/cu_up/pdu_session_manager_impl.cpp b/lib/cu_up/pdu_session_manager_impl.cpp index bbf52ec0a3..be85645315 100644 --- a/lib/cu_up/pdu_session_manager_impl.cpp +++ b/lib/cu_up/pdu_session_manager_impl.cpp @@ -28,7 +28,9 @@ pdu_session_manager_impl::pdu_session_manager_impl(ue_index_t n3_interface_config& n3_config_, cu_up_ue_logger& logger_, unique_timer& ue_inactivity_timer_, - timer_factory timers_, + timer_factory ue_dl_timer_factory_, + timer_factory ue_ul_timer_factory_, + timer_factory ue_ctrl_timer_factory_, f1u_cu_up_gateway& f1u_gw_, gtpu_teid_pool& f1u_teid_allocator_, gtpu_tunnel_tx_upper_layer_notifier& gtpu_tx_notifier_, @@ -44,7 +46,9 @@ pdu_session_manager_impl::pdu_session_manager_impl(ue_index_t n3_config(n3_config_), logger(logger_), ue_inactivity_timer(ue_inactivity_timer_), - timers(timers_), + ue_dl_timer_factory(ue_dl_timer_factory_), + ue_ul_timer_factory(ue_ul_timer_factory_), + ue_ctrl_timer_factory(ue_ctrl_timer_factory_), gtpu_tx_notifier(gtpu_tx_notifier_), f1u_teid_allocator(f1u_teid_allocator_), gtpu_rx_demux(gtpu_rx_demux_), @@ -144,7 +148,9 @@ drb_setup_result pdu_session_manager_impl::handle_drb_to_setup_item(pdu_session& pdcp_msg.tx_upper_cn = &new_drb->pdcp_tx_to_e1ap_adapter; pdcp_msg.rx_upper_dn = &new_drb->pdcp_to_sdap_adapter; pdcp_msg.rx_upper_cn = &new_drb->pdcp_rx_to_e1ap_adapter; - pdcp_msg.timers = timers; + pdcp_msg.ue_dl_timer_factory = ue_dl_timer_factory; + pdcp_msg.ue_ul_timer_factory = ue_ul_timer_factory; + pdcp_msg.ue_ctrl_timer_factory = ue_ctrl_timer_factory; new_drb->pdcp = srsran::create_pdcp_entity(pdcp_msg); security::sec_128_as_config sec_128 = security::truncate_config(security_info); @@ -192,7 +198,7 @@ drb_setup_result pdu_session_manager_impl::handle_drb_to_setup_item(pdu_session& new_drb->f1u_to_pdcp_adapter, new_drb->f1u_to_pdcp_adapter, ue_ul_exec, - timers, + ue_dl_timer_factory, ue_inactivity_timer); new_drb->f1u_ul_teid = f1u_ul_teid; drb_result.gtp_tunnel = f1u_ul_tunnel_addr; @@ -265,7 +271,7 @@ pdu_session_setup_result pdu_session_manager_impl::setup_pdu_session(const e1ap_ msg.rx_lower = &new_session->gtpu_to_sdap_adapter; msg.tx_upper = >pu_tx_notifier; msg.gtpu_pcap = >pu_pcap; - msg.timers = timers; + msg.ue_dl_timer_factory = ue_dl_timer_factory; new_session->gtpu = create_gtpu_tunnel_ngu(msg); // Connect adapters @@ -379,7 +385,7 @@ pdu_session_manager_impl::modify_pdu_session(const e1ap_pdu_session_res_to_modif drb->f1u_to_pdcp_adapter, drb->f1u_to_pdcp_adapter, ue_dl_exec, - timers, + ue_dl_timer_factory, ue_inactivity_timer); drb_iter->second->pdcp_to_f1u_adapter.disconnect_f1u(); diff --git a/lib/cu_up/pdu_session_manager_impl.h b/lib/cu_up/pdu_session_manager_impl.h index 0c0bdedfaa..f0b7308452 100644 --- a/lib/cu_up/pdu_session_manager_impl.h +++ b/lib/cu_up/pdu_session_manager_impl.h @@ -36,8 +36,10 @@ class pdu_session_manager_impl final : public pdu_session_manager_ctrl network_interface_config& net_config_, n3_interface_config& n3_config_, cu_up_ue_logger& logger_, - unique_timer& ue_inactivity_timer, - timer_factory timers_, + unique_timer& ue_inactivity_timer_, + timer_factory ue_dl_timer_factory_, + timer_factory ue_ul_timer_factory_, + timer_factory ue_ctrl_timer_factory_, f1u_cu_up_gateway& f1u_gw_, gtpu_teid_pool& f1u_teid_allocator_, gtpu_tunnel_tx_upper_layer_notifier& gtpu_tx_notifier_, @@ -72,7 +74,9 @@ class pdu_session_manager_impl final : public pdu_session_manager_ctrl n3_interface_config& n3_config; cu_up_ue_logger& logger; unique_timer& ue_inactivity_timer; - timer_factory timers; + timer_factory ue_dl_timer_factory; + timer_factory ue_ul_timer_factory; + timer_factory ue_ctrl_timer_factory; gtpu_tunnel_tx_upper_layer_notifier& gtpu_tx_notifier; gtpu_teid_pool& f1u_teid_allocator; gtpu_demux_ctrl& gtpu_rx_demux; diff --git a/lib/cu_up/ue_context.h b/lib/cu_up/ue_context.h index 318bb9cba7..83a65a71aa 100644 --- a/lib/cu_up/ue_context.h +++ b/lib/cu_up/ue_context.h @@ -43,7 +43,9 @@ class ue_context : public pdu_session_manager_ctrl std::unique_ptr> ue_dl_exec_, std::unique_ptr> ue_ul_exec_, std::unique_ptr> ue_ctrl_exec_, - timer_factory timers_, + timer_factory ue_dl_timer_factory_, + timer_factory ue_ul_timer_factory_, + timer_factory ue_ctrl_timer_factory_, f1u_cu_up_gateway& f1u_gw_, gtpu_teid_pool& f1u_teid_allocator_, gtpu_tunnel_tx_upper_layer_notifier& gtpu_tx_notifier_, @@ -60,7 +62,9 @@ class ue_context : public pdu_session_manager_ctrl n3_config_, logger, ue_inactivity_timer, - timers_, + ue_dl_timer_factory_, + ue_ul_timer_factory_, + ue_ctrl_timer_factory_, f1u_gw_, f1u_teid_allocator_, gtpu_tx_notifier_, @@ -72,14 +76,16 @@ class ue_context : public pdu_session_manager_ctrl ue_dl_exec(std::move(ue_dl_exec_)), ue_ul_exec(std::move(ue_ul_exec_)), ue_ctrl_exec(std::move(ue_ctrl_exec_)), - timers(timers_) + ue_dl_timer_factory(ue_dl_timer_factory_), + ue_ul_timer_factory(ue_ul_timer_factory_), + ue_ctrl_timer_factory(ue_ctrl_timer_factory_) { if (cfg.activity_level == activity_notification_level_t::ue) { if (not cfg.ue_inactivity_timeout.has_value()) { report_error( "Failed to create UE context. Activity notification level is UE, but no UE inactivity timer configured\n"); } - ue_inactivity_timer = timers.create_timer(); + ue_inactivity_timer = ue_ul_timer_factory.create_timer(); ue_inactivity_timer.set(*cfg.ue_inactivity_timeout, [this](timer_id_t /*tid*/) { on_ue_inactivity_timer_expired(); }); ue_inactivity_timer.run(); @@ -120,13 +126,25 @@ class ue_context : public pdu_session_manager_ctrl std::unique_ptr> ue_ul_exec; std::unique_ptr> ue_ctrl_exec; - timer_factory timers; - unique_timer ue_inactivity_timer; - void on_ue_inactivity_timer_expired() + timer_factory ue_dl_timer_factory; + timer_factory ue_ul_timer_factory; + timer_factory ue_ctrl_timer_factory; + + unique_timer ue_inactivity_timer; + + /// Handle expired UE inactivity timer. This function is called from a timer that is run in UE executor, + /// therefore it handovers the handling to control executor. + void on_ue_inactivity_timer_expired() { - e1ap_bearer_context_inactivity_notification msg = {}; - msg.ue_index = index; - e1ap.handle_bearer_context_inactivity_notification(msg); + auto fn = [this]() mutable { + e1ap_bearer_context_inactivity_notification msg = {}; + msg.ue_index = index; + e1ap.handle_bearer_context_inactivity_notification(msg); + }; + + if (!ue_ctrl_exec->execute(std::move(fn))) { + logger.log_warning("Could not handle expired UE inactivity handler, queue is full. ue={}", index); + } } }; diff --git a/lib/cu_up/ue_manager.cpp b/lib/cu_up/ue_manager.cpp index e7665c0c85..94ec788da8 100644 --- a/lib/cu_up/ue_manager.cpp +++ b/lib/cu_up/ue_manager.cpp @@ -64,6 +64,11 @@ ue_context* ue_manager::add_ue(const ue_context_cfg& ue_cfg) std::unique_ptr> ue_ul_exec = exec_pool.create_ul_pdu_executor(); std::unique_ptr> ue_ctrl_exec = exec_pool.create_ctrl_executor(); + // Create executor-specific timer factories + timer_factory ue_dl_timer_factory = {timers, *ue_dl_exec}; + timer_factory ue_ul_timer_factory = {timers, *ue_ul_exec}; + timer_factory ue_ctrl_timer_factory = {timers, *ue_ctrl_exec}; + // Create UE object std::unique_ptr new_ctx = std::make_unique(new_idx, ue_cfg, @@ -73,7 +78,9 @@ ue_context* ue_manager::add_ue(const ue_context_cfg& ue_cfg) std::move(ue_dl_exec), std::move(ue_ul_exec), std::move(ue_ctrl_exec), - timer_factory{timers, *ue_ctrl_exec}, + ue_dl_timer_factory, + ue_ul_timer_factory, + ue_ctrl_timer_factory, f1u_gw, f1u_teid_allocator, gtpu_tx_notifier, diff --git a/lib/f1u/cu_up/f1u_bearer_factory.cpp b/lib/f1u/cu_up/f1u_bearer_factory.cpp index b72baf8f29..c18f2dbfcf 100644 --- a/lib/f1u/cu_up/f1u_bearer_factory.cpp +++ b/lib/f1u/cu_up/f1u_bearer_factory.cpp @@ -21,7 +21,7 @@ std::unique_ptr srsran::srs_cu_up::create_f1u_bearer(uint32_t f1u_tx_pdu_notifier& tx_pdu_notifier, f1u_rx_delivery_notifier& rx_delivery_notifier, f1u_rx_sdu_notifier& rx_sdu_notifier, - timer_factory timers, + timer_factory ue_dl_timer_factory, unique_timer& ue_inactivity_timer, task_executor& ul_exec, f1u_bearer_disconnector& disconnector) @@ -32,7 +32,7 @@ std::unique_ptr srsran::srs_cu_up::create_f1u_bearer(uint32_t tx_pdu_notifier, rx_delivery_notifier, rx_sdu_notifier, - timers, + ue_dl_timer_factory, ue_inactivity_timer, ul_exec, disconnector); diff --git a/lib/f1u/cu_up/f1u_bearer_impl.cpp b/lib/f1u/cu_up/f1u_bearer_impl.cpp index 3b251db378..7f52d4a650 100644 --- a/lib/f1u/cu_up/f1u_bearer_impl.cpp +++ b/lib/f1u/cu_up/f1u_bearer_impl.cpp @@ -20,7 +20,7 @@ f1u_bearer_impl::f1u_bearer_impl(uint32_t ue_index, f1u_tx_pdu_notifier& tx_pdu_notifier_, f1u_rx_delivery_notifier& rx_delivery_notifier_, f1u_rx_sdu_notifier& rx_sdu_notifier_, - timer_factory timers, + timer_factory ue_dl_timer_factory, unique_timer& ue_inactivity_timer_, task_executor& ul_exec_, f1u_bearer_disconnector& disconnector_) : @@ -31,7 +31,7 @@ f1u_bearer_impl::f1u_bearer_impl(uint32_t ue_index, disconnector(disconnector_), ul_tnl_info(ul_tnl_info_), ul_exec(ul_exec_), - dl_notif_timer(timers.create_timer()), + dl_notif_timer(ue_dl_timer_factory.create_timer()), ue_inactivity_timer(ue_inactivity_timer_) { dl_notif_timer.set(std::chrono::milliseconds(f1u_dl_notif_time_ms), diff --git a/lib/f1u/cu_up/f1u_bearer_impl.h b/lib/f1u/cu_up/f1u_bearer_impl.h index 02edc30479..d54e139f45 100644 --- a/lib/f1u/cu_up/f1u_bearer_impl.h +++ b/lib/f1u/cu_up/f1u_bearer_impl.h @@ -30,7 +30,7 @@ class f1u_bearer_impl final : public f1u_bearer, public f1u_rx_pdu_handler, publ f1u_tx_pdu_notifier& tx_pdu_notifier_, f1u_rx_delivery_notifier& rx_delivery_notifier_, f1u_rx_sdu_notifier& rx_sdu_notifier_, - timer_factory timers, + timer_factory ue_dl_timer_factory, unique_timer& ue_inactivity_timer_, task_executor& ul_exec_, f1u_bearer_disconnector& diconnector_); diff --git a/lib/f1u/local_connector/f1u_local_connector.cpp b/lib/f1u/local_connector/f1u_local_connector.cpp index 28eb3ce526..4330cb9902 100644 --- a/lib/f1u/local_connector/f1u_local_connector.cpp +++ b/lib/f1u/local_connector/f1u_local_connector.cpp @@ -23,7 +23,7 @@ f1u_local_connector::create_cu_bearer(uint32_t ue_in srs_cu_up::f1u_rx_delivery_notifier& rx_delivery_notifier, srs_cu_up::f1u_rx_sdu_notifier& rx_sdu_notifier, task_executor& ul_exec, - timer_factory timers, + timer_factory ue_dl_timer_factory, unique_timer& ue_inactivity_timer) { logger_cu.info("Creating CU F1-U bearer with UL GTP Tunnel={}", ul_up_tnl_info); @@ -39,7 +39,7 @@ f1u_local_connector::create_cu_bearer(uint32_t ue_in *cu_tx, rx_delivery_notifier, rx_sdu_notifier, - timers, + ue_dl_timer_factory, ue_inactivity_timer, ul_exec, *this); diff --git a/lib/gtpu/gtpu_tunnel_impl_ngu.h b/lib/gtpu/gtpu_tunnel_impl_ngu.h index 1ff2441f12..d2256d80b6 100644 --- a/lib/gtpu/gtpu_tunnel_impl_ngu.h +++ b/lib/gtpu/gtpu_tunnel_impl_ngu.h @@ -27,10 +27,10 @@ class gtpu_tunnel_ngu_impl : public gtpu_tunnel_ngu dlt_pcap& gtpu_pcap, gtpu_tunnel_ngu_rx_lower_layer_notifier& rx_lower, gtpu_tunnel_tx_upper_layer_notifier& tx_upper, - timer_factory timers) : + timer_factory ue_dl_timer_factory) : logger(srslog::fetch_basic_logger("GTPU")) { - rx = std::make_unique(ue_index, cfg.rx, rx_lower, timers); + rx = std::make_unique(ue_index, cfg.rx, rx_lower, ue_dl_timer_factory); tx = std::make_unique(ue_index, cfg.tx, gtpu_pcap, tx_upper); } ~gtpu_tunnel_ngu_impl() override = default; diff --git a/lib/gtpu/gtpu_tunnel_ngu_factory.cpp b/lib/gtpu/gtpu_tunnel_ngu_factory.cpp index 464d71c2fc..a721c62d62 100644 --- a/lib/gtpu/gtpu_tunnel_ngu_factory.cpp +++ b/lib/gtpu/gtpu_tunnel_ngu_factory.cpp @@ -18,5 +18,5 @@ using namespace srsran; std::unique_ptr srsran::create_gtpu_tunnel_ngu(gtpu_tunnel_ngu_creation_message& msg) { return std::make_unique( - msg.ue_index, msg.cfg, *msg.gtpu_pcap, *msg.rx_lower, *msg.tx_upper, msg.timers); + msg.ue_index, msg.cfg, *msg.gtpu_pcap, *msg.rx_lower, *msg.tx_upper, msg.ue_dl_timer_factory); } diff --git a/lib/gtpu/gtpu_tunnel_ngu_rx.h b/lib/gtpu/gtpu_tunnel_ngu_rx.h index bab8858e04..0016100db6 100644 --- a/lib/gtpu/gtpu_tunnel_ngu_rx.h +++ b/lib/gtpu/gtpu_tunnel_ngu_rx.h @@ -40,23 +40,23 @@ struct gtpu_rx_sdu_info { optional sn = {}; }; -/// Class used for receiving GTP-U bearers. +/// Class used for receiving GTP-U NGU bearers, e.g. on N3 interface. class gtpu_tunnel_ngu_rx : public gtpu_tunnel_base_rx { public: gtpu_tunnel_ngu_rx(srs_cu_up::ue_index_t ue_index, gtpu_config::gtpu_rx_config cfg, gtpu_tunnel_ngu_rx_lower_layer_notifier& rx_lower_, - timer_factory timers_) : + timer_factory ue_dl_timer_factory_) : gtpu_tunnel_base_rx(gtpu_tunnel_log_prefix{ue_index, cfg.local_teid, "DL"}), psup_packer(logger.get_basic_logger()), lower_dn(rx_lower_), config(cfg), rx_window(std::make_unique>(logger)), - timers(timers_) + ue_dl_timer_factory(ue_dl_timer_factory_) { if (config.t_reordering.count() != 0) { - reordering_timer = timers.create_timer(); + reordering_timer = ue_dl_timer_factory.create_timer(); reordering_timer.set(config.t_reordering, reordering_callback{this}); } logger.log_info( @@ -247,7 +247,7 @@ class gtpu_tunnel_ngu_rx : public gtpu_tunnel_base_rx unique_timer reordering_timer; /// Timer factory - timer_factory timers; + timer_factory ue_dl_timer_factory; /// Reordering callback (t-Reordering) class reordering_callback diff --git a/lib/gtpu/gtpu_tunnel_ngu_tx.h b/lib/gtpu/gtpu_tunnel_ngu_tx.h index f29bfbb836..3e07c7e269 100644 --- a/lib/gtpu/gtpu_tunnel_ngu_tx.h +++ b/lib/gtpu/gtpu_tunnel_ngu_tx.h @@ -22,7 +22,7 @@ namespace srsran { -/// Class used for transmitting GTP-U bearers. +/// Class used for transmitting GTP-U NGU bearers, e.g. on N3 interface. class gtpu_tunnel_ngu_tx : public gtpu_tunnel_base_tx, public gtpu_tunnel_tx_lower_layer_interface { public: diff --git a/lib/pdcp/pdcp_entity_impl.h b/lib/pdcp/pdcp_entity_impl.h index d822aabe21..3198970fc6 100644 --- a/lib/pdcp/pdcp_entity_impl.h +++ b/lib/pdcp/pdcp_entity_impl.h @@ -29,13 +29,17 @@ class pdcp_entity_impl : public pdcp_entity pdcp_tx_upper_control_notifier& tx_upper_cn, pdcp_rx_upper_data_notifier& rx_upper_dn, pdcp_rx_upper_control_notifier& rx_upper_cn, - timer_factory timers) : + timer_factory ue_dl_timer_factory, + timer_factory ue_ul_timer_factory, + timer_factory ue_ctrl_timer_factory) : logger("PDCP", {ue_index, rb_id, "DL/UL"}), metrics_period(config.custom.metrics_period), - metrics_timer(timers.create_timer()) + metrics_timer(ue_ctrl_timer_factory.create_timer()) { - tx = std::make_unique(ue_index, rb_id, config.get_tx_config(), tx_lower_dn, tx_upper_cn, timers); - rx = std::make_unique(ue_index, rb_id, config.get_rx_config(), rx_upper_dn, rx_upper_cn, timers); + tx = std::make_unique( + ue_index, rb_id, config.get_tx_config(), tx_lower_dn, tx_upper_cn, ue_dl_timer_factory); + rx = std::make_unique( + ue_index, rb_id, config.get_rx_config(), rx_upper_dn, rx_upper_cn, ue_ul_timer_factory); // Tx/Rx interconnect tx->set_status_provider(rx.get()); diff --git a/lib/pdcp/pdcp_entity_rx.cpp b/lib/pdcp/pdcp_entity_rx.cpp index 5848615cb1..48b540a742 100644 --- a/lib/pdcp/pdcp_entity_rx.cpp +++ b/lib/pdcp/pdcp_entity_rx.cpp @@ -22,7 +22,7 @@ pdcp_entity_rx::pdcp_entity_rx(uint32_t ue_index, pdcp_rx_config cfg_, pdcp_rx_upper_data_notifier& upper_dn_, pdcp_rx_upper_control_notifier& upper_cn_, - timer_factory timers_) : + timer_factory ue_ul_timer_factory_) : pdcp_entity_tx_rx_base(rb_id_, cfg_.rb_type, cfg_.rlc_mode, cfg_.sn_size), logger("PDCP", {ue_index, rb_id_, "UL"}), cfg(cfg_), @@ -31,11 +31,11 @@ pdcp_entity_rx::pdcp_entity_rx(uint32_t ue_index, rx_window(create_rx_window(cfg.sn_size)), upper_dn(upper_dn_), upper_cn(upper_cn_), - timers(timers_) + ue_ul_timer_factory(ue_ul_timer_factory_) { // t-Reordering timer if (cfg.t_reordering != pdcp_t_reordering::ms0 && cfg.t_reordering != pdcp_t_reordering::infinity) { - reordering_timer = timers.create_timer(); + reordering_timer = ue_ul_timer_factory.create_timer(); if (static_cast(cfg.t_reordering) > 0) { reordering_timer.set(std::chrono::milliseconds{static_cast(cfg.t_reordering)}, reordering_callback{this}); diff --git a/lib/pdcp/pdcp_entity_rx.h b/lib/pdcp/pdcp_entity_rx.h index 5a41e45217..3952839c08 100644 --- a/lib/pdcp/pdcp_entity_rx.h +++ b/lib/pdcp/pdcp_entity_rx.h @@ -57,7 +57,7 @@ class pdcp_entity_rx final : public pdcp_entity_tx_rx_base, pdcp_rx_config cfg_, pdcp_rx_upper_data_notifier& upper_dn_, pdcp_rx_upper_control_notifier& upper_cn_, - timer_factory timers); + timer_factory ue_ul_timer_factory_); void handle_pdu(byte_buffer_chain buf) override; @@ -191,7 +191,7 @@ class pdcp_entity_rx final : public pdcp_entity_tx_rx_base, pdcp_rx_upper_data_notifier& upper_dn; pdcp_rx_upper_control_notifier& upper_cn; - timer_factory timers; + timer_factory ue_ul_timer_factory; /// Creates the rx_window according to sn_size /// \param sn_size Size of the sequence number (SN) diff --git a/lib/pdcp/pdcp_entity_tx.cpp b/lib/pdcp/pdcp_entity_tx.cpp index edae23b757..6f4f7fd988 100644 --- a/lib/pdcp/pdcp_entity_tx.cpp +++ b/lib/pdcp/pdcp_entity_tx.cpp @@ -104,7 +104,7 @@ void pdcp_entity_tx::handle_sdu(byte_buffer buf) unique_timer discard_timer = {}; // Only start for finite durations if (cfg.discard_timer.value() != pdcp_discard_timer::infinity) { - discard_timer = timers.create_timer(); + discard_timer = ue_dl_timer_factory.create_timer(); discard_timer.set(std::chrono::milliseconds(static_cast(cfg.discard_timer.value())), discard_callback{this, st.tx_next}); discard_timer.run(); diff --git a/lib/pdcp/pdcp_entity_tx.h b/lib/pdcp/pdcp_entity_tx.h index e9410e12eb..9f0c5022a1 100644 --- a/lib/pdcp/pdcp_entity_tx.h +++ b/lib/pdcp/pdcp_entity_tx.h @@ -65,13 +65,13 @@ class pdcp_entity_tx final : public pdcp_entity_tx_rx_base, pdcp_tx_config cfg_, pdcp_tx_lower_notifier& lower_dn_, pdcp_tx_upper_control_notifier& upper_cn_, - timer_factory timers_) : + timer_factory ue_dl_timer_factory_) : pdcp_entity_tx_rx_base(rb_id_, cfg_.rb_type, cfg_.rlc_mode, cfg_.sn_size), logger("PDCP", {ue_index, rb_id_, "DL"}), cfg(cfg_), lower_dn(lower_dn_), upper_cn(upper_cn_), - timers(timers_), + ue_dl_timer_factory(ue_dl_timer_factory_), tx_window(create_tx_window(cfg.sn_size)) { // Validate configuration @@ -212,7 +212,7 @@ class pdcp_entity_tx final : public pdcp_entity_tx_rx_base, pdcp_rx_status_provider* status_provider = nullptr; pdcp_tx_lower_notifier& lower_dn; pdcp_tx_upper_control_notifier& upper_cn; - timer_factory timers; + timer_factory ue_dl_timer_factory; pdcp_tx_state st = {}; security::security_direction direction = security::security_direction::downlink; diff --git a/lib/pdcp/pdcp_factory.cpp b/lib/pdcp/pdcp_factory.cpp index 7c7dab9611..21304982d0 100644 --- a/lib/pdcp/pdcp_factory.cpp +++ b/lib/pdcp/pdcp_factory.cpp @@ -24,5 +24,7 @@ std::unique_ptr srsran::create_pdcp_entity(pdcp_entity_creation_mes *msg.tx_upper_cn, *msg.rx_upper_dn, *msg.rx_upper_cn, - msg.timers); + msg.ue_dl_timer_factory, + msg.ue_ul_timer_factory, + msg.ue_ctrl_timer_factory); } diff --git a/lib/rrc/ue/rrc_ue_srb_context.h b/lib/rrc/ue/rrc_ue_srb_context.h index b818b96b12..eb1b53a5e9 100644 --- a/lib/rrc/ue/rrc_ue_srb_context.h +++ b/lib/rrc/ue/rrc_ue_srb_context.h @@ -35,7 +35,10 @@ struct srb_pdcp_context { srb_pdcp.tx_upper_cn = &rrc_tx_control_notifier; srb_pdcp.rx_upper_dn = &rrc_rx_data_notifier; srb_pdcp.rx_upper_cn = &rrc_rx_control_notifier; - srb_pdcp.timers = timers; + // Uplink, Downlink and Control run in the same executor, hence all timer factories are the same. + srb_pdcp.ue_dl_timer_factory = timers; + srb_pdcp.ue_ul_timer_factory = timers; + srb_pdcp.ue_ctrl_timer_factory = timers; // create PDCP entity entity = create_pdcp_entity(srb_pdcp); diff --git a/tests/integrationtests/rlc/rlc_stress_test.cpp b/tests/integrationtests/rlc/rlc_stress_test.cpp index 50412a6057..565ab43091 100644 --- a/tests/integrationtests/rlc/rlc_stress_test.cpp +++ b/tests/integrationtests/rlc/rlc_stress_test.cpp @@ -58,7 +58,9 @@ stress_stack::stress_stack(const stress_test_args& args_, uint32_t id, rb_id_t r pdcp_msg.tx_upper_cn = rrc.get(); pdcp_msg.rx_upper_dn = traffic_sink.get(); pdcp_msg.rx_upper_cn = rrc.get(); - pdcp_msg.timers = timer_factory{timers, *ue_executor}; + pdcp_msg.ue_dl_timer_factory = timer_factory{timers, *ue_executor}; + pdcp_msg.ue_ul_timer_factory = timer_factory{timers, *ue_executor}; + pdcp_msg.ue_ctrl_timer_factory = timer_factory{timers, *ue_executor}; pdcp = create_pdcp_entity(pdcp_msg); traffic_source->set_pdcp_tx_upper(&pdcp->get_tx_upper_data_interface()); f1ap->set_pdcp_rx_lower(&pdcp->get_rx_lower_interface()); diff --git a/tests/unittests/cu_up/cu_up_test_helpers.h b/tests/unittests/cu_up/cu_up_test_helpers.h index 3d53c7b879..92cfb9f681 100644 --- a/tests/unittests/cu_up/cu_up_test_helpers.h +++ b/tests/unittests/cu_up/cu_up_test_helpers.h @@ -239,7 +239,7 @@ class dummy_f1u_gateway final : public f1u_cu_up_gateway srs_cu_up::f1u_rx_delivery_notifier& cu_delivery, srs_cu_up::f1u_rx_sdu_notifier& cu_rx, task_executor& ul_exec, - timer_factory timers, + timer_factory ue_dl_timer_factory, unique_timer& ue_inactivity_timer) override { created_ul_teid_list.push_back(ul_up_tnl_info.gtp_teid); diff --git a/tests/unittests/cu_up/pdu_session_manager_test.h b/tests/unittests/cu_up/pdu_session_manager_test.h index 413eeee4a3..0aa545f4ab 100644 --- a/tests/unittests/cu_up/pdu_session_manager_test.h +++ b/tests/unittests/cu_up/pdu_session_manager_test.h @@ -50,6 +50,8 @@ class pdu_session_manager_test : public ::testing::Test logger, ue_inactivity_timer, timers_factory, + timers_factory, + timers_factory, *f1u_gw, *f1u_allocator, *gtpu_tx_notifier, diff --git a/tests/unittests/gtpu/gtpu_tunnel_ngu_test.cpp b/tests/unittests/gtpu/gtpu_tunnel_ngu_test.cpp index da7247285c..f5b210f0de 100644 --- a/tests/unittests/gtpu/gtpu_tunnel_ngu_test.cpp +++ b/tests/unittests/gtpu/gtpu_tunnel_ngu_test.cpp @@ -118,7 +118,7 @@ TEST_F(gtpu_tunnel_ngu_test, entity_creation) msg.gtpu_pcap = &dummy_pcap; msg.rx_lower = >pu_rx; msg.tx_upper = >pu_tx; - msg.timers = timers; + msg.ue_dl_timer_factory = timers; gtpu = create_gtpu_tunnel_ngu(msg); ASSERT_NE(gtpu, nullptr); @@ -136,7 +136,7 @@ TEST_F(gtpu_tunnel_ngu_test, rx_sdu) msg.gtpu_pcap = &dummy_pcap; msg.rx_lower = >pu_rx; msg.tx_upper = >pu_tx; - msg.timers = timers; + msg.ue_dl_timer_factory = timers; gtpu = create_gtpu_tunnel_ngu(msg); sockaddr_storage orig_addr = {}; @@ -164,7 +164,7 @@ TEST_F(gtpu_tunnel_ngu_test, tx_pdu) msg.gtpu_pcap = &dummy_pcap; msg.rx_lower = >pu_rx; msg.tx_upper = >pu_tx; - msg.timers = timers; + msg.ue_dl_timer_factory = timers; gtpu = create_gtpu_tunnel_ngu(msg); byte_buffer sdu{gtpu_ping_sdu}; From 2ad8aa82cfbd96fbb324f29b45ec1df6a919e388 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Fri, 1 Mar 2024 10:55:36 +0100 Subject: [PATCH 055/140] f1u,cu_up: add unit test for UE inactivity timer --- .../f1u/cu_up/f1u_cu_up_bearer_test.cpp | 63 +++++++++++++++++-- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/tests/unittests/f1u/cu_up/f1u_cu_up_bearer_test.cpp b/tests/unittests/f1u/cu_up/f1u_cu_up_bearer_test.cpp index 4b015adc79..31daa0914a 100644 --- a/tests/unittests/f1u/cu_up/f1u_cu_up_bearer_test.cpp +++ b/tests/unittests/f1u/cu_up/f1u_cu_up_bearer_test.cpp @@ -70,6 +70,8 @@ class f1u_trx_test class f1u_cu_up_test : public ::testing::Test, public f1u_trx_test { protected: + const unsigned inactivity_time_ms = 100; + void SetUp() override { // init test's logger @@ -85,7 +87,11 @@ class f1u_cu_up_test : public ::testing::Test, public f1u_trx_test tester = std::make_unique(); drb_id_t drb_id = drb_id_t::drb1; ue_inactivity_timer = ue_timer_factory.create_timer(); - ue_inactivity_timer.set(std::chrono::milliseconds(10000), [](timer_id_t) {}); + ue_inactivity_timer.set(std::chrono::milliseconds(inactivity_time_ms), [this](timer_id_t) { + // Text + ue_inactivity_triggered = true; + }); + ue_inactivity_timer.run(); f1u = std::make_unique(0, drb_id, up_transport_layer_info{{"127.0.0.1"}, gtpu_teid_t{ul_teid_next.value()++}}, @@ -104,10 +110,12 @@ class f1u_cu_up_test : public ::testing::Test, public f1u_trx_test srslog::flush(); } - void tick() + void tick(unsigned ms = 1) { - ue_timer_manager.tick(); - ue_worker.run_pending_tasks(); + for (unsigned t = 0; t < ms; t++) { + ue_timer_manager.tick(); + ue_worker.run_pending_tasks(); + } } srslog::basic_logger& logger = srslog::fetch_basic_logger("TEST", false); @@ -118,10 +126,13 @@ class f1u_cu_up_test : public ::testing::Test, public f1u_trx_test std::unique_ptr tester; std::unique_ptr f1u; gtpu_teid_t ul_teid_next{1234}; + + bool ue_inactivity_triggered = false; }; TEST_F(f1u_cu_up_test, create_and_delete) { + EXPECT_FALSE(ue_inactivity_triggered); EXPECT_TRUE(tester->tx_msg_list.empty()); EXPECT_TRUE(tester->highest_transmitted_pdcp_sn_list.empty()); EXPECT_TRUE(tester->highest_delivered_pdcp_sn_list.empty()); @@ -208,6 +219,9 @@ TEST_F(f1u_cu_up_test, tx_discard) TEST_F(f1u_cu_up_test, tx_pdcp_pdus) { + tick(inactivity_time_ms - 1); + EXPECT_FALSE(ue_inactivity_triggered); + constexpr uint32_t pdu_size = 10; constexpr uint32_t pdcp_sn = 123; @@ -242,10 +256,17 @@ TEST_F(f1u_cu_up_test, tx_pdcp_pdus) tester->tx_msg_list.pop_front(); EXPECT_TRUE(tester->tx_msg_list.empty()); + + // DL PDUs do not restart inactivity timer (only their transmit notif), hence one more tick shall expire the timer + tick(inactivity_time_ms); + EXPECT_TRUE(ue_inactivity_triggered); } TEST_F(f1u_cu_up_test, rx_pdcp_pdus) { + tick(inactivity_time_ms - 1); + EXPECT_FALSE(ue_inactivity_triggered); + constexpr uint32_t pdu_size = 10; constexpr uint32_t pdcp_sn = 123; @@ -254,11 +275,19 @@ TEST_F(f1u_cu_up_test, rx_pdcp_pdus) msg1.t_pdu = byte_buffer_chain{rx_pdcp_pdu1.deep_copy()}; f1u->handle_pdu(std::move(msg1)); + // UL PDUs restart inactivity timer, hence further ticks shall not expire the timer + tick(inactivity_time_ms - 1); + EXPECT_FALSE(ue_inactivity_triggered); + byte_buffer rx_pdcp_pdu2 = create_sdu_byte_buffer(pdu_size, pdcp_sn + 1); nru_ul_message msg2; msg2.t_pdu = byte_buffer_chain{rx_pdcp_pdu2.deep_copy()}; f1u->handle_pdu(std::move(msg2)); + // UL PDUs restart inactivity timer, hence further ticks shall not expire the timer + tick(inactivity_time_ms - 1); + EXPECT_FALSE(ue_inactivity_triggered); + EXPECT_TRUE(tester->tx_msg_list.empty()); EXPECT_TRUE(tester->highest_transmitted_pdcp_sn_list.empty()); EXPECT_TRUE(tester->highest_delivered_pdcp_sn_list.empty()); @@ -274,10 +303,17 @@ TEST_F(f1u_cu_up_test, rx_pdcp_pdus) tester->rx_sdu_list.pop_front(); EXPECT_TRUE(tester->rx_sdu_list.empty()); + + // One more tick shall finally expire the inactivity timer + tick(inactivity_time_ms); + EXPECT_TRUE(ue_inactivity_triggered); } TEST_F(f1u_cu_up_test, rx_transmit_notification) { + tick(inactivity_time_ms - 1); + EXPECT_FALSE(ue_inactivity_triggered); + constexpr uint32_t highest_pdcp_sn = 123; nru_dl_data_delivery_status status1 = {}; @@ -286,12 +322,20 @@ TEST_F(f1u_cu_up_test, rx_transmit_notification) msg1.data_delivery_status = std::move(status1); f1u->handle_pdu(std::move(msg1)); + // Transmit notifications restart inactivity timer, hence further ticks shall not expire the timer + tick(inactivity_time_ms - 1); + EXPECT_FALSE(ue_inactivity_triggered); + nru_dl_data_delivery_status status2 = {}; status2.highest_transmitted_pdcp_sn = highest_pdcp_sn + 1; nru_ul_message msg2 = {}; msg2.data_delivery_status = std::move(status2); f1u->handle_pdu(std::move(msg2)); + // Transmit notifications restart inactivity timer, hence further ticks shall not expire the timer + tick(inactivity_time_ms - 1); + EXPECT_FALSE(ue_inactivity_triggered); + EXPECT_TRUE(tester->tx_msg_list.empty()); EXPECT_TRUE(tester->rx_sdu_list.empty()); EXPECT_TRUE(tester->highest_delivered_pdcp_sn_list.empty()); @@ -309,10 +353,17 @@ TEST_F(f1u_cu_up_test, rx_transmit_notification) tester->highest_transmitted_pdcp_sn_list.pop_front(); EXPECT_TRUE(tester->highest_transmitted_pdcp_sn_list.empty()); + + // One more tick shall finally expire the inactivity timer + tick(inactivity_time_ms); + EXPECT_TRUE(ue_inactivity_triggered); } TEST_F(f1u_cu_up_test, rx_delivery_notification) { + tick(inactivity_time_ms - 1); + EXPECT_FALSE(ue_inactivity_triggered); + constexpr uint32_t highest_pdcp_sn = 123; nru_dl_data_delivery_status status1 = {}; @@ -344,4 +395,8 @@ TEST_F(f1u_cu_up_test, rx_delivery_notification) tester->highest_delivered_pdcp_sn_list.pop_front(); EXPECT_TRUE(tester->highest_delivered_pdcp_sn_list.empty()); + + // Delivery notifications do not restart inactivity timer, hence one more tick shall expire the timer + tick(inactivity_time_ms); + EXPECT_TRUE(ue_inactivity_triggered); } From 663e418e664038bfe6a3de1dc66cab7ca03a3c86 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Wed, 21 Feb 2024 13:48:17 +0100 Subject: [PATCH 056/140] sched: allocate remaining RBs to the last UE to be scheduled PDSCH/PUSCH for the slot --- lib/scheduler/policy/scheduler_time_rr.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/scheduler/policy/scheduler_time_rr.cpp b/lib/scheduler/policy/scheduler_time_rr.cpp index 0b1532f034..282e737faa 100644 --- a/lib/scheduler/policy/scheduler_time_rr.cpp +++ b/lib/scheduler/policy/scheduler_time_rr.cpp @@ -260,6 +260,16 @@ static alloc_outcome alloc_dl_ue(const ue& u, // Limit the grant PRBs. if (not is_retx and dl_new_tx_max_nof_rbs_per_ue_per_slot.has_value()) { mcs_prbs.n_prbs = std::min(mcs_prbs.n_prbs, dl_new_tx_max_nof_rbs_per_ue_per_slot.value()); + // [Implementation-defined] + // Check whether to allocate all remaining RBs or not. This is done to ensure we allocate only X nof. UEs for + // which dl_new_tx_max_nof_rbs_per_ue_per_slot was computed. One way is by checking if the emtpy interval is + // less than 2 times the required RBs. If so, allocate all remaining RBs. NOTE: This approach won't hold good in + // case of low traffic scenario. + const unsigned twice_grant_crbs_length = + rb_helper::find_empty_interval_of_length(used_crbs, mcs_prbs.n_prbs * 2, 0).length(); + if (twice_grant_crbs_length < (mcs_prbs.n_prbs * 2)) { + mcs_prbs.n_prbs = twice_grant_crbs_length; + } } if (mcs_prbs.n_prbs == 0) { @@ -413,6 +423,14 @@ static alloc_outcome alloc_ul_ue(const ue& u, // Limit the grant PRBs. if (not is_retx and not schedule_sr_only and ul_new_tx_max_nof_rbs_per_ue_per_slot.has_value()) { mcs_prbs.n_prbs = std::min(mcs_prbs.n_prbs, ul_new_tx_max_nof_rbs_per_ue_per_slot.value()); + // [Implementation-defined] + // Check whether it's the last UE to be scheduled in this slot i.e. if the emtpy interval is less than 2 times + // the required RBs. If so, allocate all remaining RBs. + const unsigned twice_grant_crbs_length = + rb_helper::find_empty_interval_of_length(used_crbs, mcs_prbs.n_prbs * 2, 0).length(); + if (twice_grant_crbs_length < (mcs_prbs.n_prbs * 2)) { + mcs_prbs.n_prbs = twice_grant_crbs_length; + } } // NOTE: this should never happen, but it's safe not to proceed if we get n_prbs == 0. if (mcs_prbs.n_prbs == 0) { From d94fbea9f1bd2aef878de5d9c85454151889dcc7 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 20 Feb 2024 15:33:10 +0100 Subject: [PATCH 057/140] cu_cp,ngap: refactor ue context setup timer to pdu session setup timer --- apps/gnb/gnb_appconfig.h | 8 +- apps/gnb/gnb_appconfig_cli11_schema.cpp | 9 +- apps/gnb/gnb_appconfig_translators.cpp | 6 +- apps/gnb/gnb_appconfig_validators.cpp | 8 +- include/srsran/ngap/ngap_configuration.h | 2 +- .../srsran/ngap/ngap_configuration_helpers.h | 4 +- lib/ngap/ngap_context.h | 2 +- lib/ngap/ngap_impl.cpp | 84 +++++++++++-------- lib/ngap/ngap_impl.h | 3 +- lib/ngap/ue_context/ngap_ue_context.h | 4 +- tests/e2e/tests/test_mode/config_ue.yml | 2 +- tests/e2e/tests/viavi/config.yml | 2 +- .../unittests/ngap/ngap_nas_message_test.cpp | 4 +- tests/unittests/ngap/ngap_test_helpers.cpp | 2 +- 14 files changed, 79 insertions(+), 61 deletions(-) diff --git a/apps/gnb/gnb_appconfig.h b/apps/gnb/gnb_appconfig.h index 4725ca18e8..27a6dae5e3 100644 --- a/apps/gnb/gnb_appconfig.h +++ b/apps/gnb/gnb_appconfig.h @@ -717,10 +717,10 @@ struct security_appconfig { }; struct cu_cp_appconfig { - uint16_t max_nof_dus = 6; - uint16_t max_nof_cu_ups = 6; - int inactivity_timer = 5; // in seconds - unsigned ue_context_setup_timeout_s = 3; // in seconds (must be larger than T310) + uint16_t max_nof_dus = 6; + uint16_t max_nof_cu_ups = 6; + int inactivity_timer = 5; // in seconds + unsigned pdu_session_setup_timeout_s = 3; // in seconds (must be larger than T310) mobility_appconfig mobility_config; rrc_appconfig rrc_config; security_appconfig security_config; diff --git a/apps/gnb/gnb_appconfig_cli11_schema.cpp b/apps/gnb/gnb_appconfig_cli11_schema.cpp index d7d571a3b3..92f9ddafdc 100644 --- a/apps/gnb/gnb_appconfig_cli11_schema.cpp +++ b/apps/gnb/gnb_appconfig_cli11_schema.cpp @@ -422,11 +422,10 @@ static void configure_cli11_cu_cp_args(CLI::App& app, cu_cp_appconfig& cu_cp_par ->capture_default_str() ->check(CLI::Range(1, 7200)); - app.add_option( - "--ue_context_setup_timeout_s", - cu_cp_params.ue_context_setup_timeout_s, - "Timeout for the reception of an InitialContextSetupRequest after an InitialUeMessage was sent to the " - "core, in seconds. The timeout must be larger than T310. If the value is reached, the UE will be released") + app.add_option("--pdu_session_setup_timeout_s", + cu_cp_params.pdu_session_setup_timeout_s, + "Timeout for the setup of a PDU session after an InitialUeMessage was sent to the core, in " + "seconds. The timeout must be larger than T310. If the value is reached, the UE will be released") ->capture_default_str(); CLI::App* mobility_subcmd = app.add_subcommand("mobility", "Mobility configuration"); diff --git a/apps/gnb/gnb_appconfig_translators.cpp b/apps/gnb/gnb_appconfig_translators.cpp index 18a2fa91d5..4c23ce3038 100644 --- a/apps/gnb/gnb_appconfig_translators.cpp +++ b/apps/gnb/gnb_appconfig_translators.cpp @@ -129,9 +129,9 @@ srs_cu_cp::cu_cp_configuration srsran::generate_cu_cp_config(const gnb_appconfig config.cu_cp_cfg.security_config.confidentiality_protection); } - out_cfg.ue_config.inactivity_timer = std::chrono::seconds{config.cu_cp_cfg.inactivity_timer}; - out_cfg.ue_config.max_nof_supported_ues = config.cu_cp_cfg.max_nof_dus * srsran::srs_cu_cp::MAX_NOF_UES_PER_DU; - out_cfg.ngap_config.ue_context_setup_timeout = std::chrono::seconds{config.cu_cp_cfg.ue_context_setup_timeout_s}; + out_cfg.ue_config.inactivity_timer = std::chrono::seconds{config.cu_cp_cfg.inactivity_timer}; + out_cfg.ue_config.max_nof_supported_ues = config.cu_cp_cfg.max_nof_dus * srsran::srs_cu_cp::MAX_NOF_UES_PER_DU; + out_cfg.ngap_config.pdu_session_setup_timeout = std::chrono::seconds{config.cu_cp_cfg.pdu_session_setup_timeout_s}; out_cfg.statistics_report_period = std::chrono::seconds{config.metrics_cfg.cu_cp_statistics_report_period}; out_cfg.mobility_config.mobility_manager_config.trigger_handover_from_measurements = diff --git a/apps/gnb/gnb_appconfig_validators.cpp b/apps/gnb/gnb_appconfig_validators.cpp index 4c91f0e077..9c98b719e6 100644 --- a/apps/gnb/gnb_appconfig_validators.cpp +++ b/apps/gnb/gnb_appconfig_validators.cpp @@ -610,10 +610,10 @@ static bool validate_amf_appconfig(const amf_appconfig& config) /// Validates the given CU-CP configuration. Returns true on success, otherwise false. static bool validate_cu_cp_appconfig(const cu_cp_appconfig& config, const sib_appconfig& sib_cfg) { - // only check if the ue_context_setup_timout is larger than T310 - if (config.ue_context_setup_timeout_s * 1000 < sib_cfg.ue_timers_and_constants.t310) { - fmt::print("ue_context_setup_timeout_s ({}ms) must be larger than T310 ({}ms)\n", - config.ue_context_setup_timeout_s * 1000, + // only check if the pdu_session_setup_timout is larger than T310 + if (config.pdu_session_setup_timeout_s * 1000 < sib_cfg.ue_timers_and_constants.t310) { + fmt::print("pdu_session_setup_timeout_s ({}ms) must be larger than T310 ({}ms)\n", + config.pdu_session_setup_timeout_s * 1000, sib_cfg.ue_timers_and_constants.t310); return false; } diff --git a/include/srsran/ngap/ngap_configuration.h b/include/srsran/ngap/ngap_configuration.h index 3d03ecdaf6..b71477caaa 100644 --- a/include/srsran/ngap/ngap_configuration.h +++ b/include/srsran/ngap/ngap_configuration.h @@ -26,7 +26,7 @@ struct ngap_configuration { std::string plmn; /// Full PLMN as string (without possible filler digit) e.g. "00101" unsigned tac; std::vector slice_configurations; - std::chrono::seconds ue_context_setup_timeout; // timeout for ue context setup in seconds + std::chrono::seconds pdu_session_setup_timeout; // timeout for pdu session setup in seconds }; } // namespace srs_cu_cp diff --git a/include/srsran/ngap/ngap_configuration_helpers.h b/include/srsran/ngap/ngap_configuration_helpers.h index 943bd9c32f..33982215cf 100644 --- a/include/srsran/ngap/ngap_configuration_helpers.h +++ b/include/srsran/ngap/ngap_configuration_helpers.h @@ -27,8 +27,8 @@ inline srs_cu_cp::ngap_configuration make_default_ngap_config() cfg.plmn = "00101"; cfg.tac = 7; s_nssai_t slice_cfg; - slice_cfg.sst = 1; - cfg.ue_context_setup_timeout = std::chrono::seconds{2}; + slice_cfg.sst = 1; + cfg.pdu_session_setup_timeout = std::chrono::seconds{2}; cfg.slice_configurations.push_back(slice_cfg); return cfg; diff --git a/lib/ngap/ngap_context.h b/lib/ngap/ngap_context.h index ed5c0f8328..3b90f26731 100644 --- a/lib/ngap/ngap_context.h +++ b/lib/ngap/ngap_context.h @@ -25,7 +25,7 @@ struct ngap_context_t { unsigned tac; std::vector served_guami_list; guami_t current_guami; - std::chrono::seconds ue_context_setup_timeout_s; // timeout for ue context setup in seconds + std::chrono::seconds pdu_session_setup_timeout_s; // timeout for PDU context setup in seconds }; } // namespace srs_cu_cp diff --git a/lib/ngap/ngap_impl.cpp b/lib/ngap/ngap_impl.cpp index afa5e4a048..3b82234ce0 100644 --- a/lib/ngap/ngap_impl.cpp +++ b/lib/ngap/ngap_impl.cpp @@ -47,11 +47,11 @@ ngap_impl::ngap_impl(ngap_configuration& ngap_cfg_, ctrl_exec(ctrl_exec_), ev_mng(timer_factory{task_sched.get_timer_manager(), ctrl_exec}) { - context.gnb_id = ngap_cfg_.gnb_id; - context.ran_node_name = ngap_cfg_.ran_node_name; - context.plmn = ngap_cfg_.plmn; - context.tac = ngap_cfg_.tac; - context.ue_context_setup_timeout_s = ngap_cfg_.ue_context_setup_timeout; + context.gnb_id = ngap_cfg_.gnb_id; + context.ran_node_name = ngap_cfg_.ran_node_name; + context.plmn = ngap_cfg_.plmn; + context.tac = ngap_cfg_.tac; + context.pdu_session_setup_timeout_s = ngap_cfg_.pdu_session_setup_timeout; } // Note: For fwd declaration of member types, dtor cannot be trivial. @@ -138,14 +138,14 @@ void ngap_impl::handle_initial_ue_message(const cu_cp_initial_ue_message& msg) fill_asn1_initial_ue_message(init_ue_msg, msg, context); - // Start UE context setup timer - ue_ctxt.ue_context_setup_timer.set(context.ue_context_setup_timeout_s, [this, msg](timer_id_t /*tid*/) { - on_ue_context_setup_timer_expired(msg.ue_index); + // Start PDU session setup timer + ue_ctxt.pdu_session_setup_timer.set(context.pdu_session_setup_timeout_s, [this, msg](timer_id_t /*tid*/) { + on_pdu_session_setup_timer_expired(msg.ue_index); }); - ue_ctxt.ue_context_setup_timer.run(); + ue_ctxt.pdu_session_setup_timer.run(); - ue_ctxt.logger.log_debug("Sending InitialUeMessage (timeout={}ms)", - ue_ctxt.ue_context_setup_timer.duration().count()); + ue_ctxt.logger.log_debug("Sending InitialUeMessage (PDU session timeout={}ms)", + ue_ctxt.pdu_session_setup_timer.duration().count()); // Forward message to AMF ngap_notifier.on_new_message(ngap_msg); @@ -313,8 +313,10 @@ void ngap_impl::handle_initial_context_setup_request(const asn1::ngap::init_cont ue_ctxt.ue_ids.ran_ue_id, ue_ctxt.ue_ids.amf_ue_id); - // Stop UE context setup timer - ue_ctxt.ue_context_setup_timer.stop(); + // If InitialContextSetupRequest contains PDU Session Setup list, stop pdu session setup timer + if (request->pdu_session_res_setup_list_cxt_req_present) { + ue_ctxt.pdu_session_setup_timer.stop(); + } ue_ctxt.logger.log_info("Received InitialContextSetupRequest"); @@ -382,6 +384,9 @@ void ngap_impl::handle_pdu_session_resource_setup_request(const asn1::ngap::pdu_ ue_ctxt.ue_ids.ran_ue_id, ue_ctxt.ue_ids.amf_ue_id); + // Stop PDU session setup timer + ue_ctxt.pdu_session_setup_timer.stop(); + if (!ue->get_rrc_ue_control_notifier().on_security_enabled()) { ue_ctxt.logger.log_warning("Dropping PduSessionResourceSetupRequest. Security context does not exist"); send_error_indication(ngap_notifier, logger, ue_ctxt.ue_ids.ran_ue_id, ue_ctxt.ue_ids.amf_ue_id, {}); @@ -878,31 +883,44 @@ void ngap_impl::schedule_error_indication(ue_index_t ue_index, cause_t cause, op })); } -void ngap_impl::on_ue_context_setup_timer_expired(ue_index_t ue_index) +void ngap_impl::on_pdu_session_setup_timer_expired(ue_index_t ue_index) { if (ue_ctxt_list.contains(ue_index)) { ngap_ue_context& ue_ctxt = ue_ctxt_list[ue_index]; - ue_ctxt.logger.log_warning("UE context setup timer expired after {}ms. Releasing UE from DU", - ue_ctxt.ue_context_setup_timer.duration().count()); - - auto* ue = ue_manager.find_ngap_ue(ue_ctxt.ue_ids.ue_index); - srsran_assert(ue != nullptr, - "ue={} ran_ue_id={} amf_ue_id={}: UE for UE context doesn't exist", - ue_ctxt.ue_ids.ue_index, - ue_ctxt.ue_ids.ran_ue_id, - ue_ctxt.ue_ids.amf_ue_id); - - task_sched.schedule_async_task(ue_index, launch_async([ue, ue_index](coro_context>& ctx) { - CORO_BEGIN(ctx); - CORO_AWAIT( - ue->get_du_processor_control_notifier().on_new_ue_context_release_command( - {ue_index, cause_nas_t::unspecified})); - CORO_RETURN(); - })); - + if (ue_ctxt.ue_ids.amf_ue_id == amf_ue_id_t::invalid) { + // AMF never responded to InitialUEMessage, so we only remove the UE from the DU + ue_ctxt.logger.log_warning("PDU session setup timer expired after {}ms. Releasing UE from DU", + ue_ctxt.pdu_session_setup_timer.duration().count()); + + auto* ue = ue_manager.find_ngap_ue(ue_ctxt.ue_ids.ue_index); + srsran_assert(ue != nullptr, + "ue={} ran_ue_id={} amf_ue_id={}: UE for UE context doesn't exist", + ue_ctxt.ue_ids.ue_index, + ue_ctxt.ue_ids.ran_ue_id, + ue_ctxt.ue_ids.amf_ue_id); + + task_sched.schedule_async_task(ue_index, launch_async([ue, ue_index](coro_context>& ctx) { + CORO_BEGIN(ctx); + CORO_AWAIT( + ue->get_du_processor_control_notifier().on_new_ue_context_release_command( + {ue_index, cause_nas_t::unspecified})); + CORO_RETURN(); + })); + } else { + ue_ctxt.logger.log_warning("PDU session setup timer expired after {}ms. Requesting UE release", + ue_ctxt.pdu_session_setup_timer.duration().count()); + + // Request UE release + task_sched.schedule_async_task(ue_index, launch_async([this, ue_index](coro_context>& ctx) { + CORO_BEGIN(ctx); + CORO_AWAIT(handle_ue_context_release_request( + cu_cp_ue_context_release_request{ue_index, {}, cause_nas_t::unspecified})); + CORO_RETURN(); + })); + } } else { - logger.debug("ue={}: Ignoring expired UE context setup timer. UE context not found", ue_index); + logger.debug("ue={}: Ignoring expired PDU session setup timer. UE context not found", ue_index); return; } } diff --git a/lib/ngap/ngap_impl.h b/lib/ngap/ngap_impl.h index 6a197baaaf..f8e83b1a1c 100644 --- a/lib/ngap/ngap_impl.h +++ b/lib/ngap/ngap_impl.h @@ -127,7 +127,8 @@ class ngap_impl final : public ngap_interface /// \param[in] amf_ue_id The AMF UE ID. void schedule_error_indication(ue_index_t ue_index, cause_t cause, optional amf_ue_id = {}); - void on_ue_context_setup_timer_expired(ue_index_t ue_index); + /// \brief Callback for the PDU Session Setup Timer expiration. Triggers the release of the UE. + void on_pdu_session_setup_timer_expired(ue_index_t ue_index); ngap_context_t context; diff --git a/lib/ngap/ue_context/ngap_ue_context.h b/lib/ngap/ue_context/ngap_ue_context.h index 7ef5f8196a..49b6205720 100644 --- a/lib/ngap/ue_context/ngap_ue_context.h +++ b/lib/ngap/ue_context/ngap_ue_context.h @@ -27,7 +27,7 @@ struct ngap_ue_ids { struct ngap_ue_context { ngap_ue_ids ue_ids; uint64_t aggregate_maximum_bit_rate_dl = 0; - unique_timer ue_context_setup_timer = {}; + unique_timer pdu_session_setup_timer = {}; bool release_requested = false; bool release_scheduled = false; byte_buffer last_pdu_session_resource_modify_request; // To check if a received modify request is a duplicate @@ -36,7 +36,7 @@ struct ngap_ue_context { ngap_ue_context(ue_index_t ue_index_, ran_ue_id_t ran_ue_id_, timer_manager& timers_, task_executor& task_exec_) : ue_ids({ue_index_, ran_ue_id_}), logger("NGAP", {ue_index_, ran_ue_id_}) { - ue_context_setup_timer = timers_.create_unique_timer(task_exec_); + pdu_session_setup_timer = timers_.create_unique_timer(task_exec_); } }; diff --git a/tests/e2e/tests/test_mode/config_ue.yml b/tests/e2e/tests/test_mode/config_ue.yml index de261c0cf4..daf7a743f5 100644 --- a/tests/e2e/tests/test_mode/config_ue.yml +++ b/tests/e2e/tests/test_mode/config_ue.yml @@ -7,7 +7,7 @@ # cu_cp: - ue_context_setup_timeout_s: 5 + pdu_session_setup_timeout_s: 5 inactivity_timer: 3 rrc: force_reestablishment_fallback: false diff --git a/tests/e2e/tests/viavi/config.yml b/tests/e2e/tests/viavi/config.yml index 4ac1583819..9a5b261ad2 100644 --- a/tests/e2e/tests/viavi/config.yml +++ b/tests/e2e/tests/viavi/config.yml @@ -7,7 +7,7 @@ # cu_cp: - ue_context_setup_timeout_s: 5 + pdu_session_setup_timeout_s: 5 inactivity_timer: 5 rrc: force_reestablishment_fallback: true diff --git a/tests/unittests/ngap/ngap_nas_message_test.cpp b/tests/unittests/ngap/ngap_nas_message_test.cpp index 3d4d85d5c7..71729d6e9d 100644 --- a/tests/unittests/ngap/ngap_nas_message_test.cpp +++ b/tests/unittests/ngap/ngap_nas_message_test.cpp @@ -83,8 +83,8 @@ TEST_F(ngap_nas_message_routine_test, when_initial_context_setup_request_is_not_ ASSERT_EQ(ngap->get_nof_ues(), 1); // tick timers - // Status: NGAP does not receive new Initial Context Setup Request until ue_context_setup_timer has ended. - for (unsigned msec_elapsed = 0; msec_elapsed < cfg.ue_context_setup_timeout.count() * 1000; ++msec_elapsed) { + // Status: NGAP does not receive new Initial Context Setup Request until pdu_session_setup_timer has ended. + for (unsigned msec_elapsed = 0; msec_elapsed < cfg.pdu_session_setup_timeout.count() * 1000; ++msec_elapsed) { this->tick(); } diff --git a/tests/unittests/ngap/ngap_test_helpers.cpp b/tests/unittests/ngap/ngap_test_helpers.cpp index 507eb68580..895cb4b8d7 100644 --- a/tests/unittests/ngap/ngap_test_helpers.cpp +++ b/tests/unittests/ngap/ngap_test_helpers.cpp @@ -34,7 +34,7 @@ ngap_test::ngap_test() : ngap_ue_task_scheduler(timers, ctrl_worker) s_nssai_t slice_cfg; slice_cfg.sst = 1; cfg.slice_configurations.push_back(slice_cfg); - cfg.ue_context_setup_timeout = std::chrono::seconds(2); + cfg.pdu_session_setup_timeout = std::chrono::seconds(2); ngap = create_ngap( cfg, ngap_ue_creation_notifier, cu_cp_paging_notifier, ngap_ue_task_scheduler, ue_mng, msg_notifier, ctrl_worker); From d4361bfc1804c87d1d8dd5eb9aa1ba62ed427ac8 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 20 Feb 2024 15:33:28 +0100 Subject: [PATCH 058/140] cu_cp, ngap: add unittest for pdu session setup timer --- ..._session_resource_setup_procedure_test.cpp | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/unittests/ngap/ngap_pdu_session_resource_setup_procedure_test.cpp b/tests/unittests/ngap/ngap_pdu_session_resource_setup_procedure_test.cpp index 0b71abecd3..b65652628f 100644 --- a/tests/unittests/ngap/ngap_pdu_session_resource_setup_procedure_test.cpp +++ b/tests/unittests/ngap/ngap_pdu_session_resource_setup_procedure_test.cpp @@ -95,6 +95,33 @@ class ngap_pdu_session_resource_setup_procedure_test : public ngap_test } }; +/// Test missing PDU Session Resource Setup Request +TEST_F(ngap_pdu_session_resource_setup_procedure_test, + when_pdu_session_resource_setup_request_is_not_received_then_ue_release_is_requested) +{ + ASSERT_EQ(ngap->get_nof_ues(), 0); + + // Test preamble + this->start_procedure(); + + // check that initial context setup request was received to the AMF and that UE object has been created + ASSERT_EQ(msg_notifier.last_ngap_msgs.back().pdu.type().value, + asn1::ngap::ngap_pdu_c::types_opts::successful_outcome); + ASSERT_EQ(msg_notifier.last_ngap_msgs.back().pdu.successful_outcome().value.type(), + asn1::ngap::ngap_elem_procs_o::successful_outcome_c::types_opts::init_context_setup_resp); + ASSERT_EQ(ngap->get_nof_ues(), 1); + + // tick timers + // Status: NGAP does not receive new PDU Session Resource Setup Request until pdu_session_setup_timer has ended. + for (unsigned msec_elapsed = 0; msec_elapsed < cfg.pdu_session_setup_timeout.count() * 1000; ++msec_elapsed) { + this->tick(); + } + + // check that UE release was requested + ASSERT_EQ(msg_notifier.last_ngap_msgs.back().pdu.init_msg().value.type(), + asn1::ngap::ngap_elem_procs_o::init_msg_c::types_opts::ue_context_release_request); +} + /// Test valid PDU Session Resource Setup Request TEST_F(ngap_pdu_session_resource_setup_procedure_test, when_valid_pdu_session_resource_setup_request_received_then_pdu_session_setup_succeeds) From 939168ede5698e9f9a0a308876c89b52b81ebfbf Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 20 Feb 2024 15:52:14 +0100 Subject: [PATCH 059/140] gnb,ngap: remove _s suffix from config value --- apps/gnb/gnb_appconfig.h | 8 ++++---- apps/gnb/gnb_appconfig_cli11_schema.cpp | 4 ++-- apps/gnb/gnb_appconfig_translators.cpp | 2 +- apps/gnb/gnb_appconfig_validators.cpp | 6 +++--- lib/ngap/ngap_context.h | 2 +- lib/ngap/ngap_impl.cpp | 12 ++++++------ tests/e2e/tests/test_mode/config_ue.yml | 2 +- tests/e2e/tests/viavi/config.yml | 2 +- 8 files changed, 19 insertions(+), 19 deletions(-) diff --git a/apps/gnb/gnb_appconfig.h b/apps/gnb/gnb_appconfig.h index 27a6dae5e3..bfad124701 100644 --- a/apps/gnb/gnb_appconfig.h +++ b/apps/gnb/gnb_appconfig.h @@ -717,10 +717,10 @@ struct security_appconfig { }; struct cu_cp_appconfig { - uint16_t max_nof_dus = 6; - uint16_t max_nof_cu_ups = 6; - int inactivity_timer = 5; // in seconds - unsigned pdu_session_setup_timeout_s = 3; // in seconds (must be larger than T310) + uint16_t max_nof_dus = 6; + uint16_t max_nof_cu_ups = 6; + int inactivity_timer = 5; // in seconds + unsigned pdu_session_setup_timeout = 3; // in seconds (must be larger than T310) mobility_appconfig mobility_config; rrc_appconfig rrc_config; security_appconfig security_config; diff --git a/apps/gnb/gnb_appconfig_cli11_schema.cpp b/apps/gnb/gnb_appconfig_cli11_schema.cpp index 92f9ddafdc..95cbdffeb5 100644 --- a/apps/gnb/gnb_appconfig_cli11_schema.cpp +++ b/apps/gnb/gnb_appconfig_cli11_schema.cpp @@ -422,8 +422,8 @@ static void configure_cli11_cu_cp_args(CLI::App& app, cu_cp_appconfig& cu_cp_par ->capture_default_str() ->check(CLI::Range(1, 7200)); - app.add_option("--pdu_session_setup_timeout_s", - cu_cp_params.pdu_session_setup_timeout_s, + app.add_option("--pdu_session_setup_timeout", + cu_cp_params.pdu_session_setup_timeout, "Timeout for the setup of a PDU session after an InitialUeMessage was sent to the core, in " "seconds. The timeout must be larger than T310. If the value is reached, the UE will be released") ->capture_default_str(); diff --git a/apps/gnb/gnb_appconfig_translators.cpp b/apps/gnb/gnb_appconfig_translators.cpp index 4c23ce3038..5ac36411c0 100644 --- a/apps/gnb/gnb_appconfig_translators.cpp +++ b/apps/gnb/gnb_appconfig_translators.cpp @@ -131,7 +131,7 @@ srs_cu_cp::cu_cp_configuration srsran::generate_cu_cp_config(const gnb_appconfig out_cfg.ue_config.inactivity_timer = std::chrono::seconds{config.cu_cp_cfg.inactivity_timer}; out_cfg.ue_config.max_nof_supported_ues = config.cu_cp_cfg.max_nof_dus * srsran::srs_cu_cp::MAX_NOF_UES_PER_DU; - out_cfg.ngap_config.pdu_session_setup_timeout = std::chrono::seconds{config.cu_cp_cfg.pdu_session_setup_timeout_s}; + out_cfg.ngap_config.pdu_session_setup_timeout = std::chrono::seconds{config.cu_cp_cfg.pdu_session_setup_timeout}; out_cfg.statistics_report_period = std::chrono::seconds{config.metrics_cfg.cu_cp_statistics_report_period}; out_cfg.mobility_config.mobility_manager_config.trigger_handover_from_measurements = diff --git a/apps/gnb/gnb_appconfig_validators.cpp b/apps/gnb/gnb_appconfig_validators.cpp index 9c98b719e6..391d22a6c5 100644 --- a/apps/gnb/gnb_appconfig_validators.cpp +++ b/apps/gnb/gnb_appconfig_validators.cpp @@ -611,9 +611,9 @@ static bool validate_amf_appconfig(const amf_appconfig& config) static bool validate_cu_cp_appconfig(const cu_cp_appconfig& config, const sib_appconfig& sib_cfg) { // only check if the pdu_session_setup_timout is larger than T310 - if (config.pdu_session_setup_timeout_s * 1000 < sib_cfg.ue_timers_and_constants.t310) { - fmt::print("pdu_session_setup_timeout_s ({}ms) must be larger than T310 ({}ms)\n", - config.pdu_session_setup_timeout_s * 1000, + if (config.pdu_session_setup_timeout * 1000 < sib_cfg.ue_timers_and_constants.t310) { + fmt::print("pdu_session_setup_timeout ({}ms) must be larger than T310 ({}ms)\n", + config.pdu_session_setup_timeout * 1000, sib_cfg.ue_timers_and_constants.t310); return false; } diff --git a/lib/ngap/ngap_context.h b/lib/ngap/ngap_context.h index 3b90f26731..c6320226c8 100644 --- a/lib/ngap/ngap_context.h +++ b/lib/ngap/ngap_context.h @@ -25,7 +25,7 @@ struct ngap_context_t { unsigned tac; std::vector served_guami_list; guami_t current_guami; - std::chrono::seconds pdu_session_setup_timeout_s; // timeout for PDU context setup in seconds + std::chrono::seconds pdu_session_setup_timeout; // timeout for PDU context setup in seconds }; } // namespace srs_cu_cp diff --git a/lib/ngap/ngap_impl.cpp b/lib/ngap/ngap_impl.cpp index 3b82234ce0..8890b0d423 100644 --- a/lib/ngap/ngap_impl.cpp +++ b/lib/ngap/ngap_impl.cpp @@ -47,11 +47,11 @@ ngap_impl::ngap_impl(ngap_configuration& ngap_cfg_, ctrl_exec(ctrl_exec_), ev_mng(timer_factory{task_sched.get_timer_manager(), ctrl_exec}) { - context.gnb_id = ngap_cfg_.gnb_id; - context.ran_node_name = ngap_cfg_.ran_node_name; - context.plmn = ngap_cfg_.plmn; - context.tac = ngap_cfg_.tac; - context.pdu_session_setup_timeout_s = ngap_cfg_.pdu_session_setup_timeout; + context.gnb_id = ngap_cfg_.gnb_id; + context.ran_node_name = ngap_cfg_.ran_node_name; + context.plmn = ngap_cfg_.plmn; + context.tac = ngap_cfg_.tac; + context.pdu_session_setup_timeout = ngap_cfg_.pdu_session_setup_timeout; } // Note: For fwd declaration of member types, dtor cannot be trivial. @@ -139,7 +139,7 @@ void ngap_impl::handle_initial_ue_message(const cu_cp_initial_ue_message& msg) fill_asn1_initial_ue_message(init_ue_msg, msg, context); // Start PDU session setup timer - ue_ctxt.pdu_session_setup_timer.set(context.pdu_session_setup_timeout_s, [this, msg](timer_id_t /*tid*/) { + ue_ctxt.pdu_session_setup_timer.set(context.pdu_session_setup_timeout, [this, msg](timer_id_t /*tid*/) { on_pdu_session_setup_timer_expired(msg.ue_index); }); ue_ctxt.pdu_session_setup_timer.run(); diff --git a/tests/e2e/tests/test_mode/config_ue.yml b/tests/e2e/tests/test_mode/config_ue.yml index daf7a743f5..3da5fb9530 100644 --- a/tests/e2e/tests/test_mode/config_ue.yml +++ b/tests/e2e/tests/test_mode/config_ue.yml @@ -7,7 +7,7 @@ # cu_cp: - pdu_session_setup_timeout_s: 5 + pdu_session_setup_timeout: 5 inactivity_timer: 3 rrc: force_reestablishment_fallback: false diff --git a/tests/e2e/tests/viavi/config.yml b/tests/e2e/tests/viavi/config.yml index 9a5b261ad2..e87b0cae13 100644 --- a/tests/e2e/tests/viavi/config.yml +++ b/tests/e2e/tests/viavi/config.yml @@ -7,7 +7,7 @@ # cu_cp: - pdu_session_setup_timeout_s: 5 + pdu_session_setup_timeout: 5 inactivity_timer: 5 rrc: force_reestablishment_fallback: true From f96df64c24811031af7cf5bb2c124ca4e1abd82f Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 22 Feb 2024 12:09:56 +0100 Subject: [PATCH 060/140] cu_cp,ngap: stop pdu session timer when release is requested --- lib/ngap/ngap_impl.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/ngap/ngap_impl.cpp b/lib/ngap/ngap_impl.cpp index 8890b0d423..5c2c96be40 100644 --- a/lib/ngap/ngap_impl.cpp +++ b/lib/ngap/ngap_impl.cpp @@ -754,6 +754,9 @@ async_task ngap_impl::handle_ue_context_release_request(const cu_cp_ue_con ngap_ue_context& ue_ctxt = ue_ctxt_list[msg.ue_index]; + // Stop PDU session setup timer + ue_ctxt.pdu_session_setup_timer.stop(); + if (ue_ctxt.ue_ids.amf_ue_id == amf_ue_id_t::invalid) { ue_ctxt.logger.log_debug("Ignoring UeContextReleaseRequest. UE does not have an AMF UE ID"); return launch_async([](coro_context>& ctx) { From 474ee7c8bb7828af48bd95e8a814d4be0e786c7a Mon Sep 17 00:00:00 2001 From: asaezper Date: Tue, 27 Feb 2024 18:45:49 +0100 Subject: [PATCH 061/140] ui: handle multiple cells --- .gitlab/ci/e2e/.env | 2 +- docker/grafana/dashboards/home.json | 167 +++++++----------- docker/metrics_server/pyproject.toml | 2 +- .../src/metrics_server/__main__.py | 2 + 4 files changed, 68 insertions(+), 105 deletions(-) diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index 2a8eadab19..9c2cc255e3 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -5,7 +5,7 @@ AMARISOFT_VERSION=2023-03-17 SRSUE_VERSION=23.11 OPEN5GS_VERSION=2.6.1 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin -METRICS_SERVER_VERSION=1.6.0 +METRICS_SERVER_VERSION=1.7.0 DPDK_VERSION=23.11 ZMQ_HOSTLABEL_0=kubernetes.io/hostname=k8s-worker-vm2 ZMQ_HOSTLABEL_1=kubernetes.io/hostname=k8s-worker-vm2 diff --git a/docker/grafana/dashboards/home.json b/docker/grafana/dashboards/home.json index dbb47a7f58..f594693244 100644 --- a/docker/grafana/dashboards/home.json +++ b/docker/grafana/dashboards/home.json @@ -57,7 +57,6 @@ "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": null, "links": [], "liveNow": false, "panels": [ @@ -97,30 +96,29 @@ "color": { "mode": "thresholds" }, + "decimals": 0, "mappings": [], + "min": 0, "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null - }, - { - "color": "red", - "value": 80 } ] - } + }, + "unit": "none" }, "overrides": [] }, "gridPos": { "h": 4, - "w": 3, + "w": 2, "x": 4, "y": 0 }, - "id": 12, + "id": 19, "options": { "colorMode": "value", "graphMode": "none", @@ -128,12 +126,14 @@ "orientation": "auto", "reduceOptions": { "calcs": [ - "last" + "lastNotNull" ], "fields": "", "values": false }, - "textMode": "auto" + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true }, "pluginVersion": "10.2.0-61719", "targets": [ @@ -142,12 +142,20 @@ "type": "influxdb", "uid": "JOSE3g9KVz" }, - "query": "from(bucket: \"srsran\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"ue_info\")\n |> filter(fn: (r) => r[\"testbed\"] == \"default\")\n |> filter(fn: (r) => r[\"_field\"] == \"dl_brate\")\n |> group(columns: [\"_time\"])\n |> count(column: \"rnti\")\n |> map(fn: (r) => ({ r with _value: r[\"rnti\"] }))\n |> drop(columns: [\"rnti\"])\n |> group()", - "refId": "A" + "query": "from(bucket: \"srsran\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"ue_info\")\n |> filter(fn: (r) => r[\"testbed\"] == \"default\")\n |> filter(fn: (r) => r[\"_field\"] == \"dl_brate\")\n |> window(every: 2s)\n |> group(columns: [\"_stop\"])\n |> unique(column: \"pci\")\n |> count(column: \"pci\")\n |> map(fn: (r) => ({ r with _value: r[\"pci\"] }))\n |> drop(columns: [\"pci\"])\n |> group()\n", + "refId": "Downlink" + } + ], + "title": "Num Cells", + "transformations": [ + { + "id": "renameByRegex", + "options": { + "regex": ".*", + "renamePattern": "Num Cells" + } } ], - "title": "Active UEs", - "transparent": true, "type": "stat" }, { @@ -159,41 +167,7 @@ "fieldConfig": { "defaults": { "color": { - "mode": "palette-classic" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": 30000, - "lineInterpolation": "linear", - "lineStyle": { - "fill": "solid" - }, - "lineWidth": 1, - "pointSize": 7, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "dashed" - } + "mode": "thresholds" }, "decimals": 0, "mappings": [], @@ -213,30 +187,35 @@ }, "gridPos": { "h": 4, - "w": 5, - "x": 7, + "w": 6, + "x": 6, "y": 0 }, "id": 14, "options": { - "legend": { - "calcs": [], - "displayMode": "table", - "placement": "right", - "showLegend": false + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false }, - "tooltip": { - "mode": "single", - "sort": "none" - } + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true }, + "pluginVersion": "10.2.0-61719", "targets": [ { "datasource": { "type": "influxdb", "uid": "JOSE3g9KVz" }, - "query": "from(bucket: \"srsran\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"ue_info\")\n |> filter(fn: (r) => r[\"testbed\"] == \"default\")\n |> filter(fn: (r) => r[\"_field\"] == \"dl_brate\")\n |> group(columns: [\"_time\"])\n |> count(column: \"rnti\")\n |> map(fn: (r) => ({ r with _value: r[\"rnti\"] }))\n |> drop(columns: [\"rnti\"])\n |> group()", + "query": "from(bucket: \"srsran\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"ue_info\")\n |> filter(fn: (r) => r[\"testbed\"] == \"default\")\n |> filter(fn: (r) => r[\"_field\"] == \"dl_brate\")\n |> map(fn: (r) => ({ r with ue_id: r[\"pci\"]+\".\"+r[\"rnti\"]}))\n |> window(every: 2s)\n |> group(columns: [\"_stop\"])\n |> unique(column: \"ue_id\")\n |> count(column: \"ue_id\")\n |> map(fn: (r) => ({ r with _value: r[\"ue_id\"] }))\n |> drop(columns: [\"ue_id\"])\n |> group()\n", "refId": "Downlink" } ], @@ -250,7 +229,7 @@ } } ], - "type": "timeseries" + "type": "stat" }, { "datasource": { @@ -296,7 +275,9 @@ "fields": "", "values": false }, - "textMode": "auto" + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true }, "pluginVersion": "10.2.0-62263", "targets": [ @@ -305,23 +286,12 @@ "type": "influxdb", "uid": "JOSE3g9KVz" }, - "query": "from(bucket: \"srsran\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"ue_info\")\n |> filter(fn: (r) => r[\"testbed\"] == \"default\")\n |> filter(fn: (r) => r[\"_field\"] == \"dl_brate\")", + "query": "from(bucket: \"srsran\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"ue_info\")\n |> filter(fn: (r) => r[\"testbed\"] == \"default\")\n |> filter(fn: (r) => r[\"_field\"] == \"dl_brate\")\n |> window(every: 1s)\n |> group(columns: [\"_stop\"])\n |> sum(column: \"_value\")\n |> group()\n |> movingAverage(n: 2)\n ", "refId": "A" } ], "title": "Current Total Downlink Bitrate", - "transformations": [ - { - "id": "calculateField", - "options": { - "mode": "reduceRow", - "reduce": { - "reducer": "sum" - }, - "replaceFields": true - } - } - ], + "transformations": [], "type": "stat" }, { @@ -368,7 +338,9 @@ "fields": "", "values": false }, - "textMode": "auto" + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true }, "pluginVersion": "10.2.0-61719", "targets": [ @@ -377,23 +349,12 @@ "type": "influxdb", "uid": "JOSE3g9KVz" }, - "query": "from(bucket: \"srsran\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"ue_info\")\n |> filter(fn: (r) => r[\"testbed\"] == \"default\")\n |> filter(fn: (r) => r[\"_field\"] == \"dl_brate\")", + "query": "from(bucket: \"srsran\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"ue_info\")\n |> filter(fn: (r) => r[\"testbed\"] == \"default\")\n |> filter(fn: (r) => r[\"_field\"] == \"dl_brate\")\n |> window(every: 1s)\n |> group(columns: [\"_stop\"])\n |> sum(column: \"_value\")\n |> group()\n |> movingAverage(n: 2)\n ", "refId": "A" } ], "title": "Maximum Total Downlink Bitrate", - "transformations": [ - { - "id": "calculateField", - "options": { - "mode": "reduceRow", - "reduce": { - "reducer": "sum" - }, - "replaceFields": true - } - } - ], + "transformations": [], "type": "stat" }, { @@ -489,8 +450,8 @@ { "id": "renameByRegex", "options": { - "regex": ".*rnti=\"(\\w+).*$", - "renamePattern": "UE $1" + "regex": ".*pci=\"(\\w+).*rnti=\"(\\w+).*$", + "renamePattern": "UE $2 [$1]" } } ], @@ -594,8 +555,8 @@ { "id": "renameByRegex", "options": { - "regex": ".*rnti=\"(\\w+).*$", - "renamePattern": "UE $1" + "regex": ".*pci=\"(\\w+).*rnti=\"(\\w+).*$", + "renamePattern": "UE $2 [$1]" } } ], @@ -694,8 +655,8 @@ { "id": "renameByRegex", "options": { - "regex": ".*rnti=\"(\\w+).*$", - "renamePattern": "UE $1" + "regex": ".*pci=\"(\\w+).*rnti=\"(\\w+).*$", + "renamePattern": "UE $2 [$1]" } } ], @@ -799,8 +760,8 @@ { "id": "renameByRegex", "options": { - "regex": ".*rnti=\"(\\w+).*$", - "renamePattern": "UE $1" + "regex": ".*pci=\"(\\w+).*rnti=\"(\\w+).*$", + "renamePattern": "UE $2 [$1]" } } ], @@ -904,8 +865,8 @@ { "id": "renameByRegex", "options": { - "regex": ".*rnti=\"(\\w+).*$", - "renamePattern": "UE $1" + "regex": ".*pci=\"(\\w+).*rnti=\"(\\w+).*$", + "renamePattern": "UE $2 [$1]" } } ], @@ -1009,8 +970,8 @@ { "id": "renameByRegex", "options": { - "regex": ".*rnti=\"(\\w+).*$", - "renamePattern": "UE $1" + "regex": ".*pci=\"(\\w+).*rnti=\"(\\w+).*$", + "renamePattern": "UE $2 [$1]" } } ], @@ -1046,6 +1007,6 @@ "timezone": "", "title": "srsRAN Project Metrics", "uid": "a8a69f8a-1dd1-4496-8f3f-33de8988a823", - "version": 1, + "version": 2, "weekStart": "" } \ No newline at end of file diff --git a/docker/metrics_server/pyproject.toml b/docker/metrics_server/pyproject.toml index 9cea0a9b75..8207ffdc2c 100644 --- a/docker/metrics_server/pyproject.toml +++ b/docker/metrics_server/pyproject.toml @@ -31,7 +31,7 @@ description = "srsRAN Metrics Server" name = "srs_metrics_server" readme = "README.md" requires-python = ">=3.7" -version = "1.6.0" +version = "1.7.0" [project.scripts] metrics-server = "metrics_server.__main__:main" diff --git a/docker/metrics_server/src/metrics_server/__main__.py b/docker/metrics_server/src/metrics_server/__main__.py index 996d285205..04ffd5a43b 100644 --- a/docker/metrics_server/src/metrics_server/__main__.py +++ b/docker/metrics_server/src/metrics_server/__main__.py @@ -153,12 +153,14 @@ def _publish_data( for ue_info in metric["ue_list"]: ue_container = ue_info["ue_container"] rnti = ue_container.pop("rnti") + pci = ue_container.pop("pci") _influx_push( write_api, bucket=bucket, record={ "measurement": "ue_info", "tags": { + "pci": pci, "rnti": f"{rnti:x}", "testbed": testbed, }, From 746f2f72d5708a0a86b875b53f6cc80823c71f45 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 4 Mar 2024 15:01:28 +0100 Subject: [PATCH 062/140] phy: walks around unitialized error --- lib/srsvec/conversion.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/srsvec/conversion.cpp b/lib/srsvec/conversion.cpp index efd26f54c7..7812d562fc 100644 --- a/lib/srsvec/conversion.cpp +++ b/lib/srsvec/conversion.cpp @@ -84,7 +84,7 @@ static inline void convert_if_simd(float* z, const int16_t* x, float scale, unsi __m256i input_vec = _mm256_maskz_loadu_epi16(mask, reinterpret_cast(x + i)); // Convert the int16_t elements to float and scale them. - __m512 float_vec = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(input_vec)); + __m512 float_vec = _mm512_maskz_cvtepi32_ps(mask, _mm512_maskz_cvtepi16_epi32(mask, input_vec)); float_vec = _mm512_mul_ps(float_vec, scale512); // Store the result back to memory. From ceda60d99b5ced8bcefff17da4ba9de0ca676911 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 27 Feb 2024 10:30:34 +0100 Subject: [PATCH 063/140] cu_cp,f1ap,e1ap: fix misc cause conversion --- lib/e1ap/common/e1ap_asn1_converters.h | 14 ++++++++++++-- lib/f1ap/cu_cp/f1ap_asn1_converters.h | 7 ++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/e1ap/common/e1ap_asn1_converters.h b/lib/e1ap/common/e1ap_asn1_converters.h index 19fc3ae097..c2b7cdace5 100644 --- a/lib/e1ap/common/e1ap_asn1_converters.h +++ b/lib/e1ap/common/e1ap_asn1_converters.h @@ -986,7 +986,12 @@ inline cause_t e1ap_cause_to_cause(asn1::e1ap::cause_c e1ap_cause) cause = static_cast(e1ap_cause.protocol().value); break; case asn1::e1ap::cause_c::types_opts::misc: - cause = static_cast(e1ap_cause.misc().value); + // The mapping is not 1:1, so we need to handle the unspecified case separately + if (e1ap_cause.misc().value == asn1::e1ap::cause_misc_opts::unspecified) { + cause = cause_misc_t::unspecified; + } else { + cause = static_cast(e1ap_cause.misc().value); + } break; default: report_fatal_error("Cannot convert E1AP ASN.1 cause {} to common type", e1ap_cause.type()); @@ -1012,7 +1017,12 @@ inline asn1::e1ap::cause_c cause_to_asn1_cause(cause_t cause) e1ap_cause.set_protocol() = static_cast(variant_get(cause)); } else if (variant_holds_alternative(cause)) { - e1ap_cause.set_misc() = static_cast(variant_get(cause)); + // The mapping is not 1:1, so we need to handle the unspecified case separately + if (variant_get(cause) == cause_misc_t::unspecified) { + e1ap_cause.set_misc() = asn1::e1ap::cause_misc_opts::unspecified; + } else { + e1ap_cause.set_misc() = static_cast(variant_get(cause)); + } } else { report_fatal_error("Cannot convert cause to E1AP type"); } diff --git a/lib/f1ap/cu_cp/f1ap_asn1_converters.h b/lib/f1ap/cu_cp/f1ap_asn1_converters.h index db57fe9b12..405ec71fcf 100644 --- a/lib/f1ap/cu_cp/f1ap_asn1_converters.h +++ b/lib/f1ap/cu_cp/f1ap_asn1_converters.h @@ -41,7 +41,12 @@ inline cause_t f1ap_asn1_to_cause(asn1::f1ap::cause_c f1ap_cause) cause = static_cast(f1ap_cause.protocol().value); break; case asn1::f1ap::cause_c::types_opts::misc: - cause = static_cast(f1ap_cause.misc().value); + // The mapping is not 1:1, so we need to handle the unspecified case separately + if (f1ap_cause.misc().value == asn1::f1ap::cause_misc_opts::unspecified) { + cause = cause_misc_t::unspecified; + } else { + cause = static_cast(f1ap_cause.misc().value); + } break; default: report_fatal_error("Cannot convert F1AP ASN.1 cause {} to common type", f1ap_cause.type()); From 957f22b8701a8db9ce8ac17a781562748663e031 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 27 Feb 2024 10:49:38 +0100 Subject: [PATCH 064/140] cu_cp,ngap,f1ap,e1ap: fix transport cause conversion --- include/srsran/ran/cause.h | 11 ++++++--- lib/e1ap/common/e1ap_asn1_converters.h | 31 +++++++++++++++++++++----- lib/f1ap/cu_cp/f1ap_asn1_converters.h | 30 +++++++++++++++++++++---- lib/ngap/ngap_asn1_converters.h | 7 +++++- 4 files changed, 65 insertions(+), 14 deletions(-) diff --git a/include/srsran/ran/cause.h b/include/srsran/ran/cause.h index 702232a48c..c638a5897f 100644 --- a/include/srsran/ran/cause.h +++ b/include/srsran/ran/cause.h @@ -62,9 +62,14 @@ enum class cause_radio_network_t : uint8_t { release_due_to_cn_detected_mob }; -enum class cause_transport_t : uint8_t { transport_res_unavailable = 0, unspecified }; +enum class cause_transport_t : uint8_t { + transport_res_unavailable = 0, + unspecified, + unknown_tnl_address_for_iab, // only F1AP and E1AP + unknown_up_tnl_info_for_iab // only F1AP +}; -enum class cause_nas_t : uint8_t { normal_release = 0, authentication_fail, deregister, unspecified }; +enum class cause_nas_t : uint8_t { normal_release = 0, authentication_fail, deregister, unspecified }; // only NGAP enum class cause_protocol_t : uint8_t { transfer_syntax_error = 0, @@ -81,7 +86,7 @@ enum class cause_misc_t : uint8_t { not_enough_user_plane_processing_res, hardware_fail, om_intervention, - unknown_plmn_or_sn_pn, + unknown_plmn_or_sn_pn, // only NGAP unspecified }; diff --git a/lib/e1ap/common/e1ap_asn1_converters.h b/lib/e1ap/common/e1ap_asn1_converters.h index c2b7cdace5..24e956b540 100644 --- a/lib/e1ap/common/e1ap_asn1_converters.h +++ b/lib/e1ap/common/e1ap_asn1_converters.h @@ -10,11 +10,8 @@ #pragma once -#include "srsran/adt/byte_buffer.h" #include "srsran/adt/optional.h" -#include "srsran/adt/static_vector.h" #include "srsran/asn1/asn1_utils.h" -#include "srsran/asn1/e1ap/e1ap.h" #include "srsran/asn1/e1ap/e1ap_ies.h" #include "srsran/cu_cp/cu_cp_types.h" #include "srsran/e1ap/cu_cp/e1ap_cu_cp.h" @@ -980,9 +977,20 @@ inline cause_t e1ap_cause_to_cause(asn1::e1ap::cause_c e1ap_cause) cause = static_cast(e1ap_cause.radio_network().value); break; case asn1::e1ap::cause_c::types_opts::transport: - cause = static_cast(e1ap_cause.transport().value); + // The mapping is not 1:1, so we need to handle most cases separately + switch (e1ap_cause.transport().value) { + case asn1::e1ap::cause_transport_opts::transport_res_unavailable: + cause = cause_transport_t::transport_res_unavailable; + break; + case asn1::e1ap::cause_transport_opts::unspecified: + cause = cause_transport_t::unspecified; + break; + default: + cause = static_cast(e1ap_cause.transport().value); + } break; case asn1::e1ap::cause_c::types_opts::protocol: + // The mapping is 1:1 so we can directly convert the value cause = static_cast(e1ap_cause.protocol().value); break; case asn1::e1ap::cause_c::types_opts::misc: @@ -1011,9 +1019,20 @@ inline asn1::e1ap::cause_c cause_to_asn1_cause(cause_t cause) e1ap_cause.set_radio_network() = static_cast(variant_get(cause)); } else if (variant_holds_alternative(cause)) { - e1ap_cause.set_transport() = - static_cast(variant_get(cause)); + // The mapping is not 1:1, so we need to handle most cases separately + switch (variant_get(cause)) { + case cause_transport_t::transport_res_unavailable: + e1ap_cause.set_transport() = asn1::e1ap::cause_transport_opts::transport_res_unavailable; + break; + case cause_transport_t::unspecified: + e1ap_cause.set_transport() = asn1::e1ap::cause_transport_opts::unspecified; + break; + default: + e1ap_cause.set_transport() = + static_cast(variant_get(cause)); + } } else if (variant_holds_alternative(cause)) { + // The mapping is 1:1 so we can directly convert the value e1ap_cause.set_protocol() = static_cast(variant_get(cause)); } else if (variant_holds_alternative(cause)) { diff --git a/lib/f1ap/cu_cp/f1ap_asn1_converters.h b/lib/f1ap/cu_cp/f1ap_asn1_converters.h index 405ec71fcf..57288b7eb0 100644 --- a/lib/f1ap/cu_cp/f1ap_asn1_converters.h +++ b/lib/f1ap/cu_cp/f1ap_asn1_converters.h @@ -14,8 +14,8 @@ #include "srsran/asn1/f1ap/common.h" #include "srsran/asn1/f1ap/f1ap_ies.h" #include "srsran/cu_cp/cu_cp_types.h" -#include "srsran/f1ap/cu_cp/du_setup_notifier.h" #include "srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h" +#include "srsran/ran/cause.h" #include "srsran/ran/nr_cgi.h" #include #include @@ -35,9 +35,20 @@ inline cause_t f1ap_asn1_to_cause(asn1::f1ap::cause_c f1ap_cause) cause = static_cast(f1ap_cause.radio_network().value); break; case asn1::f1ap::cause_c::types_opts::transport: - cause = static_cast(f1ap_cause.transport().value); + // The mapping is not 1:1, so we need to handle most cases separately + switch (f1ap_cause.transport().value) { + case asn1::f1ap::cause_transport_opts::transport_res_unavailable: + cause = cause_transport_t::transport_res_unavailable; + break; + case asn1::f1ap::cause_transport_opts::unspecified: + cause = cause_transport_t::unspecified; + break; + default: + cause = static_cast(f1ap_cause.transport().value); + } break; case asn1::f1ap::cause_c::types_opts::protocol: + // The mapping is 1:1 so we can directly convert the value cause = static_cast(f1ap_cause.protocol().value); break; case asn1::f1ap::cause_c::types_opts::misc: @@ -68,9 +79,20 @@ inline asn1::f1ap::cause_c cause_to_f1ap_asn1(cause_t cause) f1ap_cause.set_radio_network() = static_cast(variant_get(cause)); } else if (variant_holds_alternative(cause)) { - f1ap_cause.set_transport() = - static_cast(variant_get(cause)); + // The mapping is not 1:1, so we need to handle most cases separately + switch (variant_get(cause)) { + case cause_transport_t::transport_res_unavailable: + f1ap_cause.set_transport() = asn1::f1ap::cause_transport_opts::transport_res_unavailable; + break; + case cause_transport_t::unspecified: + f1ap_cause.set_transport() = asn1::f1ap::cause_transport_opts::unspecified; + break; + default: + f1ap_cause.set_transport() = + static_cast(variant_get(cause)); + } } else if (variant_holds_alternative(cause)) { + // The mapping is 1:1 so we can directly convert the value f1ap_cause.set_protocol() = static_cast(variant_get(cause)); } else if (variant_holds_alternative(cause)) { diff --git a/lib/ngap/ngap_asn1_converters.h b/lib/ngap/ngap_asn1_converters.h index 218c870e8e..c5ca9b6865 100644 --- a/lib/ngap/ngap_asn1_converters.h +++ b/lib/ngap/ngap_asn1_converters.h @@ -146,7 +146,12 @@ inline cause_t asn1_to_cause(asn1::ngap::cause_c ngap_cause) cause = static_cast(ngap_cause.radio_network().value); break; case asn1::ngap::cause_c::types_opts::transport: - cause = static_cast(ngap_cause.transport().value); + // The mapping is not 1:1, so we need to handle some cases separately + if (ngap_cause.transport().value == asn1::ngap::cause_transport_opts::options::transport_res_unavailable) { + cause = cause_transport_t::transport_res_unavailable; + } else { + cause = cause_transport_t::unspecified; + } break; case asn1::ngap::cause_c::types_opts::nas: cause = static_cast(ngap_cause.nas().value); From f0e2c9b586d4276d0d9b60a6b442f69eb6abcbb9 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 27 Feb 2024 13:56:45 +0100 Subject: [PATCH 065/140] cu_cp,ngap,f1ap,e1ap: fix radio network cause conversion --- include/srsran/ran/cause.h | 106 ++++++++++--- lib/cu_cp/du_processor/du_processor_impl.cpp | 6 +- lib/e1ap/common/e1ap_asn1_converters.h | 157 ++++++++++++++++++- lib/f1ap/cu_cp/f1ap_asn1_converters.h | 123 ++++++++++++++- lib/ngap/ngap_asn1_converters.h | 106 ++++++++++++- 5 files changed, 462 insertions(+), 36 deletions(-) diff --git a/include/srsran/ran/cause.h b/include/srsran/ran/cause.h index c638a5897f..4e8872d963 100644 --- a/include/srsran/ran/cause.h +++ b/include/srsran/ran/cause.h @@ -14,9 +14,44 @@ namespace srsran { -enum class cause_radio_network_t : uint8_t { +constexpr uint16_t NGAP_RADIO_NETWORK_CAUSE_OFFSET = 100; +constexpr uint16_t F1AP_RADIO_NETWORK_CAUSE_OFFSET = 200; +constexpr uint16_t E1AP_RADIO_NETWORK_CAUSE_OFFSET = 300; + +enum class cause_radio_network_t : uint16_t { + // Common unspecified = 0, - txnrelocoverall_expiry, + interaction_with_other_proc, + res_not_available_for_the_slice, + + // NGAP and F1AP + cell_not_available, + + // NGAP and E1AP + not_supported_5qi_value, + up_integrity_protection_not_possible, + up_confidentiality_protection_not_possible, + multiple_pdu_session_id_instances, + unknown_pdu_session_id, + multiple_qos_flow_id_instances, + invalid_qos_combination, + + // F1AP and E1AP + not_supported_qci_value, + multiple_drb_id_instances, + unknown_drb_id, + proc_cancelled, + normal_release, + no_radio_res_available, + action_desirable_for_radio_reasons, + release_due_to_pre_emption, + npn_not_supported, + existing_meas_id, + meas_temporarily_not_available, + meas_not_supported_for_the_obj, + + // NGAP + txnrelocoverall_expiry = NGAP_RADIO_NETWORK_CAUSE_OFFSET + 1, successful_ho, release_due_to_ngran_generated_reason, release_due_to_5gc_generated_reason, @@ -26,8 +61,7 @@ enum class cause_radio_network_t : uint8_t { ho_target_not_allowed, tngrelocoverall_expiry, tngrelocprep_expiry, - cell_not_available, - unknown_target_id, + unknown_target_id = NGAP_RADIO_NETWORK_CAUSE_OFFSET + 12, no_radio_res_available_in_target_cell, unknown_local_ue_ngap_id, inconsistent_remote_ue_ngap_id, @@ -38,28 +72,60 @@ enum class cause_radio_network_t : uint8_t { user_inactivity, radio_conn_with_ue_lost, radio_res_not_available, - invalid_qos_combination, - fail_in_radio_interface_proc, - interaction_with_other_proc, - unknown_pdu_session_id, - unkown_qos_flow_id, - multiple_pdu_session_id_instances, - multiple_qos_flow_id_instances, - encryption_and_or_integrity_protection_algorithms_not_supported, + fail_in_radio_interface_proc = NGAP_RADIO_NETWORK_CAUSE_OFFSET + 24, + unkown_qos_flow_id = NGAP_RADIO_NETWORK_CAUSE_OFFSET + 27, + encryption_and_or_integrity_protection_algorithms_not_supported = NGAP_RADIO_NETWORK_CAUSE_OFFSET + 30, ng_intra_sys_ho_triggered, ng_inter_sys_ho_triggered, xn_ho_triggered, - not_supported_5qi_value, - ue_context_transfer, + ue_context_transfer = NGAP_RADIO_NETWORK_CAUSE_OFFSET + 35, ims_voice_eps_fallback_or_rat_fallback_triggered, - up_integrity_protection_not_possible, - up_confidentiality_protection_not_possible, - slice_not_supported, + slice_not_supported = NGAP_RADIO_NETWORK_CAUSE_OFFSET + 39, ue_in_rrc_inactive_state_not_reachable, redirection, - res_not_available_for_the_slice, - ue_max_integrity_protected_data_rate_reason, - release_due_to_cn_detected_mob + ue_max_integrity_protected_data_rate_reason = NGAP_RADIO_NETWORK_CAUSE_OFFSET + 43, + release_due_to_cn_detected_mob, + + // F1AP + rl_fail_rlc = F1AP_RADIO_NETWORK_CAUSE_OFFSET + 1, + unknown_or_already_allocated_gnb_cu_ue_f1ap_id, + unknown_or_already_allocated_gnb_du_ue_f1ap_id, + unknown_or_inconsistent_pair_of_ue_f1ap_id, + rl_fail_others = F1AP_RADIO_NETWORK_CAUSE_OFFSET + 12, + ue_rejection, + amf_initiated_abnormal_release = F1AP_RADIO_NETWORK_CAUSE_OFFSET + 15, + plmn_not_served_by_the_gnb_cu = F1AP_RADIO_NETWORK_CAUSE_OFFSET + 17, + multiple_bh_rlc_ch_id_instances = F1AP_RADIO_NETWORK_CAUSE_OFFSET + 20, + unknown_bh_rlc_ch_id, + cho_cpc_res_tobechanged, + npn_access_denied = F1AP_RADIO_NETWORK_CAUSE_OFFSET + 24, + gnb_cu_cell_capacity_exceeded, + report_characteristics_empty, + unknown_bh_address = F1AP_RADIO_NETWORK_CAUSE_OFFSET + 30, + unknown_bap_routing_id, + insufficient_ue_cap, + scg_activation_deactivation_fail, + scg_deactivation_fail_due_to_data_tx, + requested_item_not_supported_on_time, + unknown_or_already_allocated_gnb_cu_mbs_f1ap_id, + unknown_or_already_allocated_gnb_du_mbs_f1ap_id, + unknown_or_inconsistent_pair_of_mbs_f1ap_id, + unknown_or_inconsistent_mrb_id, + tat_sdt_expiry, + + // E1AP + unknown_or_already_allocated_gnb_cu_cp_ue_e1ap_id = E1AP_RADIO_NETWORK_CAUSE_OFFSET + 1, + unknown_or_already_allocated_gnb_cu_up_ue_e1ap_id, + unknown_or_inconsistent_pair_of_ue_e1ap_id, + ppdcp_count_wrap_around = E1AP_RADIO_NETWORK_CAUSE_OFFSET + 5, + encryption_algorithms_not_supported = E1AP_RADIO_NETWORK_CAUSE_OFFSET + 8, + integrity_protection_algorithms_not_supported, + unknown_qos_flow_id = E1AP_RADIO_NETWORK_CAUSE_OFFSET + 15, + pdcp_cfg_not_supported = E1AP_RADIO_NETWORK_CAUSE_OFFSET + 24, + ue_dl_max_ip_data_rate_reason, + up_integrity_protection_fail, + rsn_not_available_for_the_up = E1AP_RADIO_NETWORK_CAUSE_OFFSET + 28, + report_characteristic_empty = E1AP_RADIO_NETWORK_CAUSE_OFFSET + 30 }; enum class cause_transport_t : uint8_t { diff --git a/lib/cu_cp/du_processor/du_processor_impl.cpp b/lib/cu_cp/du_processor/du_processor_impl.cpp index f837299100..ba3a503113 100644 --- a/lib/cu_cp/du_processor/du_processor_impl.cpp +++ b/lib/cu_cp/du_processor/du_processor_impl.cpp @@ -315,10 +315,8 @@ void du_processor_impl::handle_du_initiated_ue_context_release_request(const f1a // Notify NGAP to request a release from the AMF CORO_AWAIT_VALUE(ngap_release_successful, - ngap_ctrl_notifier.on_ue_context_release_request( - cu_cp_ue_context_release_request{request.ue_index, - ue->get_up_resource_manager().get_pdu_sessions(), - cause_radio_network_t::radio_conn_with_ue_lost})); + ngap_ctrl_notifier.on_ue_context_release_request(cu_cp_ue_context_release_request{ + request.ue_index, ue->get_up_resource_manager().get_pdu_sessions(), request.cause})); if (!ngap_release_successful) { // Release UE from DU, if it doesn't exist in the NGAP logger.debug("ue={}: Releasing UE from DU. ReleaseRequest not sent to AMF", request.ue_index); diff --git a/lib/e1ap/common/e1ap_asn1_converters.h b/lib/e1ap/common/e1ap_asn1_converters.h index 24e956b540..97c07f985a 100644 --- a/lib/e1ap/common/e1ap_asn1_converters.h +++ b/lib/e1ap/common/e1ap_asn1_converters.h @@ -17,6 +17,7 @@ #include "srsran/e1ap/cu_cp/e1ap_cu_cp.h" #include "srsran/e1ap/cu_cp/e1ap_cu_cp_bearer_context_update.h" #include "srsran/ran/bcd_helpers.h" +#include "srsran/ran/cause.h" #include "srsran/ran/qos_prio_level.h" #include "srsran/support/error_handling.h" #include @@ -974,7 +975,81 @@ inline cause_t e1ap_cause_to_cause(asn1::e1ap::cause_c e1ap_cause) switch (e1ap_cause.type()) { case asn1::e1ap::cause_c::types_opts::radio_network: - cause = static_cast(e1ap_cause.radio_network().value); + switch (e1ap_cause.radio_network().value) { + // Common + case asn1::e1ap::cause_radio_network_opts::options::unspecified: + cause = cause_radio_network_t::unspecified; + break; + case asn1::e1ap::cause_radio_network_opts::options::interaction_with_other_proc: + cause = cause_radio_network_t::interaction_with_other_proc; + break; + case asn1::e1ap::cause_radio_network_opts::options::res_not_available_for_the_slice: + cause = cause_radio_network_t::res_not_available_for_the_slice; + break; + // Common for E1AP and NGAP + case asn1::e1ap::cause_radio_network_opts::options::not_supported_5qi_value: + cause = cause_radio_network_t::not_supported_5qi_value; + break; + case asn1::e1ap::cause_radio_network_opts::options::up_integrity_protection_not_possible: + cause = cause_radio_network_t::up_integrity_protection_not_possible; + break; + case asn1::e1ap::cause_radio_network_opts::options::up_confidentiality_protection_not_possible: + cause = cause_radio_network_t::up_confidentiality_protection_not_possible; + break; + case asn1::e1ap::cause_radio_network_opts::options::multiple_pdu_session_id_instances: + cause = cause_radio_network_t::multiple_pdu_session_id_instances; + break; + case asn1::e1ap::cause_radio_network_opts::options::unknown_pdu_session_id: + cause = cause_radio_network_t::unknown_pdu_session_id; + break; + case asn1::e1ap::cause_radio_network_opts::options::multiple_qos_flow_id_instances: + cause = cause_radio_network_t::multiple_qos_flow_id_instances; + break; + case asn1::e1ap::cause_radio_network_opts::options::invalid_qos_combination: + cause = cause_radio_network_t::invalid_qos_combination; + break; + // Common for E1AP and F1AP + case asn1::e1ap::cause_radio_network_opts::options::not_supported_qci_value: + cause = cause_radio_network_t::not_supported_qci_value; + break; + case asn1::e1ap::cause_radio_network_opts::options::multiple_drb_id_instances: + cause = cause_radio_network_t::multiple_drb_id_instances; + break; + case asn1::e1ap::cause_radio_network_opts::options::unknown_drb_id: + cause = cause_radio_network_t::unknown_drb_id; + break; + case asn1::e1ap::cause_radio_network_opts::options::proc_cancelled: + cause = cause_radio_network_t::proc_cancelled; + break; + case asn1::e1ap::cause_radio_network_opts::options::normal_release: + cause = cause_radio_network_t::normal_release; + break; + case asn1::e1ap::cause_radio_network_opts::options::no_radio_res_available: + cause = cause_radio_network_t::no_radio_res_available; + break; + case asn1::e1ap::cause_radio_network_opts::options::action_desirable_for_radio_reasons: + cause = cause_radio_network_t::action_desirable_for_radio_reasons; + break; + case asn1::e1ap::cause_radio_network_opts::options::release_due_to_pre_emption: + cause = cause_radio_network_t::release_due_to_pre_emption; + break; + case asn1::e1ap::cause_radio_network_opts::options::npn_not_supported: + cause = cause_radio_network_t::npn_not_supported; + break; + case asn1::e1ap::cause_radio_network_opts::options::existing_meas_id: + cause = cause_radio_network_t::existing_meas_id; + break; + case asn1::e1ap::cause_radio_network_opts::options::meas_temporarily_not_available: + cause = cause_radio_network_t::meas_temporarily_not_available; + break; + case asn1::e1ap::cause_radio_network_opts::options::meas_not_supported_for_the_obj: + cause = cause_radio_network_t::meas_not_supported_for_the_obj; + break; + // E1AP + default: + cause = + static_cast(e1ap_cause.radio_network().value + E1AP_RADIO_NETWORK_CAUSE_OFFSET); + } break; case asn1::e1ap::cause_c::types_opts::transport: // The mapping is not 1:1, so we need to handle most cases separately @@ -1016,8 +1091,84 @@ inline asn1::e1ap::cause_c cause_to_asn1_cause(cause_t cause) asn1::e1ap::cause_c e1ap_cause; if (variant_holds_alternative(cause)) { - e1ap_cause.set_radio_network() = - static_cast(variant_get(cause)); + // Convert E1AP types + if (static_cast(variant_get(cause)) >= E1AP_RADIO_NETWORK_CAUSE_OFFSET) { + e1ap_cause.set_radio_network() = static_cast( + static_cast(variant_get(cause)) - E1AP_RADIO_NETWORK_CAUSE_OFFSET); + } else { + switch (variant_get(cause)) { + // Common + case cause_radio_network_t::interaction_with_other_proc: + e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::interaction_with_other_proc; + break; + case cause_radio_network_t::res_not_available_for_the_slice: + e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::res_not_available_for_the_slice; + break; + // Common for E1AP and NGAP + case cause_radio_network_t::not_supported_5qi_value: + e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::not_supported_5qi_value; + break; + case cause_radio_network_t::up_integrity_protection_not_possible: + e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::up_integrity_protection_not_possible; + break; + case cause_radio_network_t::up_confidentiality_protection_not_possible: + e1ap_cause.set_radio_network() = + asn1::e1ap::cause_radio_network_opts::up_confidentiality_protection_not_possible; + break; + case cause_radio_network_t::multiple_pdu_session_id_instances: + e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::multiple_pdu_session_id_instances; + break; + case cause_radio_network_t::unknown_pdu_session_id: + e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::unknown_pdu_session_id; + break; + case cause_radio_network_t::multiple_qos_flow_id_instances: + e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::multiple_qos_flow_id_instances; + break; + case cause_radio_network_t::invalid_qos_combination: + e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::invalid_qos_combination; + break; + // Common for E1AP and F1AP + case cause_radio_network_t::not_supported_qci_value: + e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::not_supported_qci_value; + break; + case cause_radio_network_t::multiple_drb_id_instances: + e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::multiple_drb_id_instances; + break; + case cause_radio_network_t::unknown_drb_id: + e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::unknown_drb_id; + break; + case cause_radio_network_t::proc_cancelled: + e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::proc_cancelled; + break; + case cause_radio_network_t::normal_release: + e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::normal_release; + break; + case cause_radio_network_t::no_radio_res_available: + e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::no_radio_res_available; + break; + case cause_radio_network_t::action_desirable_for_radio_reasons: + e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::action_desirable_for_radio_reasons; + break; + case cause_radio_network_t::release_due_to_pre_emption: + e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::release_due_to_pre_emption; + break; + case cause_radio_network_t::npn_not_supported: + e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::npn_not_supported; + break; + case cause_radio_network_t::existing_meas_id: + e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::existing_meas_id; + break; + case cause_radio_network_t::meas_temporarily_not_available: + e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::meas_temporarily_not_available; + break; + case cause_radio_network_t::meas_not_supported_for_the_obj: + e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::meas_not_supported_for_the_obj; + break; + // E1AP + default: + e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::unspecified; + } + } } else if (variant_holds_alternative(cause)) { // The mapping is not 1:1, so we need to handle most cases separately switch (variant_get(cause)) { diff --git a/lib/f1ap/cu_cp/f1ap_asn1_converters.h b/lib/f1ap/cu_cp/f1ap_asn1_converters.h index 57288b7eb0..005f0af4e7 100644 --- a/lib/f1ap/cu_cp/f1ap_asn1_converters.h +++ b/lib/f1ap/cu_cp/f1ap_asn1_converters.h @@ -11,6 +11,7 @@ #pragma once #include "srsran/adt/optional.h" +#include "srsran/adt/variant.h" #include "srsran/asn1/f1ap/common.h" #include "srsran/asn1/f1ap/f1ap_ies.h" #include "srsran/cu_cp/cu_cp_types.h" @@ -32,7 +33,62 @@ inline cause_t f1ap_asn1_to_cause(asn1::f1ap::cause_c f1ap_cause) switch (f1ap_cause.type()) { case asn1::f1ap::cause_c::types_opts::radio_network: - cause = static_cast(f1ap_cause.radio_network().value); + switch (f1ap_cause.radio_network().value) { + // Common + case asn1::f1ap::cause_radio_network_opts::options::unspecified: + cause = cause_radio_network_t::unspecified; + break; + case asn1::f1ap::cause_radio_network_opts::options::interaction_with_other_proc: + cause = cause_radio_network_t::interaction_with_other_proc; + break; + case asn1::f1ap::cause_radio_network_opts::options::res_not_available_for_the_slice: + cause = cause_radio_network_t::res_not_available_for_the_slice; + break; + // Common for F1AP and NGAP + case asn1::f1ap::cause_radio_network_opts::options::cell_not_available: + cause = cause_radio_network_t::cell_not_available; + break; + // Common for F1AP and E1AP + case asn1::f1ap::cause_radio_network_opts::options::not_supported_qci_value: + cause = cause_radio_network_t::not_supported_qci_value; + break; + case asn1::f1ap::cause_radio_network_opts::options::multiple_drb_id_instances: + cause = cause_radio_network_t::multiple_drb_id_instances; + break; + case asn1::f1ap::cause_radio_network_opts::options::unknown_drb_id: + cause = cause_radio_network_t::unknown_drb_id; + break; + case asn1::f1ap::cause_radio_network_opts::options::proc_cancelled: + cause = cause_radio_network_t::proc_cancelled; + break; + case asn1::f1ap::cause_radio_network_opts::options::normal_release: + cause = cause_radio_network_t::normal_release; + break; + case asn1::f1ap::cause_radio_network_opts::options::no_radio_res_available: + cause = cause_radio_network_t::no_radio_res_available; + break; + case asn1::f1ap::cause_radio_network_opts::options::action_desirable_for_radio_reasons: + cause = cause_radio_network_t::action_desirable_for_radio_reasons; + break; + case asn1::f1ap::cause_radio_network_opts::options::release_due_to_pre_emption: + cause = cause_radio_network_t::release_due_to_pre_emption; + break; + case asn1::f1ap::cause_radio_network_opts::options::npn_not_supported: + cause = cause_radio_network_t::npn_not_supported; + break; + case asn1::f1ap::cause_radio_network_opts::options::existing_meas_id: + cause = cause_radio_network_t::existing_meas_id; + break; + case asn1::f1ap::cause_radio_network_opts::options::meas_temporarily_not_available: + cause = cause_radio_network_t::meas_temporarily_not_available; + break; + case asn1::f1ap::cause_radio_network_opts::options::meas_not_supported_for_the_obj: + cause = cause_radio_network_t::meas_not_supported_for_the_obj; + break; + // F1AP + default: + cause = static_cast(f1ap_cause.radio_network() + F1AP_RADIO_NETWORK_CAUSE_OFFSET); + } break; case asn1::f1ap::cause_c::types_opts::transport: // The mapping is not 1:1, so we need to handle most cases separately @@ -72,12 +128,67 @@ inline cause_t f1ap_asn1_to_cause(asn1::f1ap::cause_c f1ap_cause) inline asn1::f1ap::cause_c cause_to_f1ap_asn1(cause_t cause) { asn1::f1ap::cause_c f1ap_cause; - - // TODO: Fix cause mapping - if (variant_holds_alternative(cause)) { - f1ap_cause.set_radio_network() = - static_cast(variant_get(cause)); + // Convert F1AP types + if (static_cast(variant_get(cause)) >= F1AP_RADIO_NETWORK_CAUSE_OFFSET && + static_cast(variant_get(cause)) < E1AP_RADIO_NETWORK_CAUSE_OFFSET) { + f1ap_cause.set_radio_network() = static_cast( + static_cast(variant_get(cause)) - F1AP_RADIO_NETWORK_CAUSE_OFFSET); + } else { + switch (variant_get(cause)) { + // Common + case cause_radio_network_t::interaction_with_other_proc: + f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::interaction_with_other_proc; + break; + case cause_radio_network_t::res_not_available_for_the_slice: + f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::res_not_available_for_the_slice; + break; + // Common for F1AP and NGAP + case cause_radio_network_t::cell_not_available: + f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::cell_not_available; + break; + // Common for F1AP and E1AP + case cause_radio_network_t::not_supported_qci_value: + f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::not_supported_qci_value; + break; + case cause_radio_network_t::multiple_drb_id_instances: + f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::multiple_drb_id_instances; + break; + case cause_radio_network_t::unknown_drb_id: + f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::unknown_drb_id; + break; + case cause_radio_network_t::proc_cancelled: + f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::proc_cancelled; + break; + case cause_radio_network_t::normal_release: + f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::normal_release; + break; + case cause_radio_network_t::no_radio_res_available: + f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::no_radio_res_available; + break; + case cause_radio_network_t::action_desirable_for_radio_reasons: + f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::action_desirable_for_radio_reasons; + break; + case cause_radio_network_t::release_due_to_pre_emption: + f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::release_due_to_pre_emption; + break; + case cause_radio_network_t::npn_not_supported: + f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::npn_not_supported; + break; + case cause_radio_network_t::existing_meas_id: + f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::existing_meas_id; + break; + case cause_radio_network_t::meas_temporarily_not_available: + f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::meas_temporarily_not_available; + break; + case cause_radio_network_t::meas_not_supported_for_the_obj: + f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::meas_not_supported_for_the_obj; + break; + // F1AP + default: + f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::unspecified; + } + } } else if (variant_holds_alternative(cause)) { // The mapping is not 1:1, so we need to handle most cases separately switch (variant_get(cause)) { diff --git a/lib/ngap/ngap_asn1_converters.h b/lib/ngap/ngap_asn1_converters.h index c5ca9b6865..6be41fdb14 100644 --- a/lib/ngap/ngap_asn1_converters.h +++ b/lib/ngap/ngap_asn1_converters.h @@ -11,10 +11,12 @@ #pragma once #include "ngap_asn1_utils.h" +#include "srsran/adt/variant.h" #include "srsran/asn1/ngap/ngap_ies.h" #include "srsran/cu_cp/cu_cp_types.h" #include "srsran/ngap/ngap_handover.h" #include "srsran/ran/bcd_helpers.h" +#include "srsran/ran/cause.h" #include "srsran/ran/cu_types.h" #include "srsran/ran/lcid.h" #include "srsran/ran/up_transport_layer_info.h" @@ -115,8 +117,65 @@ inline asn1::ngap::cause_c cause_to_asn1(cause_t cause) asn1::ngap::cause_c ngap_cause; if (variant_holds_alternative(cause)) { - ngap_cause.set_radio_network() = - static_cast(variant_get(cause)); + // Convert NGAP types + if (static_cast(variant_get(cause)) >= NGAP_RADIO_NETWORK_CAUSE_OFFSET && + static_cast(variant_get(cause)) < F1AP_RADIO_NETWORK_CAUSE_OFFSET) { + ngap_cause.set_radio_network() = static_cast( + static_cast(variant_get(cause)) - NGAP_RADIO_NETWORK_CAUSE_OFFSET); + } else { + switch (variant_get(cause)) { + // Common type + case cause_radio_network_t::interaction_with_other_proc: + ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::interaction_with_other_proc; + break; + case cause_radio_network_t::res_not_available_for_the_slice: + ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::res_not_available_for_the_slice; + break; + // Common for NGAP and F1AP + case cause_radio_network_t::cell_not_available: + ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::cell_not_available; + break; + // Common for NGAP and E1AP + case cause_radio_network_t::not_supported_5qi_value: + ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::not_supported_5qi_value; + break; + case cause_radio_network_t::up_integrity_protection_not_possible: + ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::up_integrity_protection_not_possible; + break; + case cause_radio_network_t::up_confidentiality_protection_not_possible: + ngap_cause.set_radio_network() = + asn1::ngap::cause_radio_network_opts::up_confidentiality_protection_not_possible; + break; + case cause_radio_network_t::multiple_pdu_session_id_instances: + ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::multiple_pdu_session_id_instances; + break; + case cause_radio_network_t::unknown_pdu_session_id: + ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::unknown_pdu_session_id; + break; + case cause_radio_network_t::multiple_qos_flow_id_instances: + ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::multiple_qos_flow_id_instances; + break; + case cause_radio_network_t::invalid_qos_combination: + ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::invalid_qos_combination; + break; + // F1AP to NGAP conversion + case cause_radio_network_t::rl_fail_rlc: + ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::radio_conn_with_ue_lost; + break; + case cause_radio_network_t::rl_fail_others: + ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::radio_conn_with_ue_lost; + break; + // E1AP to NGAP conversion + case cause_radio_network_t::encryption_algorithms_not_supported: + case cause_radio_network_t::integrity_protection_algorithms_not_supported: + ngap_cause.set_radio_network() = + asn1::ngap::cause_radio_network_opts::encryption_and_or_integrity_protection_algorithms_not_supported; + break; + // NGAP + default: + ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::unspecified; + } + } } else if (variant_holds_alternative(cause)) { ngap_cause.set_transport() = static_cast(variant_get(cause)); @@ -143,7 +202,48 @@ inline cause_t asn1_to_cause(asn1::ngap::cause_c ngap_cause) switch (ngap_cause.type()) { case asn1::ngap::cause_c::types_opts::radio_network: - cause = static_cast(ngap_cause.radio_network().value); + switch (ngap_cause.radio_network().value) { + // Common + case asn1::ngap::cause_radio_network_opts::options::unspecified: + cause = cause_radio_network_t::unspecified; + break; + case asn1::ngap::cause_radio_network_opts::options::interaction_with_other_proc: + cause = cause_radio_network_t::interaction_with_other_proc; + break; + case asn1::ngap::cause_radio_network_opts::options::res_not_available_for_the_slice: + cause = cause_radio_network_t::res_not_available_for_the_slice; + break; + // Common for NGAP and F1AP + case asn1::ngap::cause_radio_network_opts::options::cell_not_available: + cause = cause_radio_network_t::cell_not_available; + break; + // Common for NGAP and E1AP + case asn1::ngap::cause_radio_network_opts::options::not_supported_5qi_value: + cause = cause_radio_network_t::not_supported_5qi_value; + break; + case asn1::ngap::cause_radio_network_opts::options::up_integrity_protection_not_possible: + cause = cause_radio_network_t::up_integrity_protection_not_possible; + break; + case asn1::ngap::cause_radio_network_opts::options::up_confidentiality_protection_not_possible: + cause = cause_radio_network_t::up_confidentiality_protection_not_possible; + break; + case asn1::ngap::cause_radio_network_opts::options::multiple_pdu_session_id_instances: + cause = cause_radio_network_t::multiple_pdu_session_id_instances; + break; + case asn1::ngap::cause_radio_network_opts::options::unknown_pdu_session_id: + cause = cause_radio_network_t::unknown_pdu_session_id; + break; + case asn1::ngap::cause_radio_network_opts::options::multiple_qos_flow_id_instances: + cause = cause_radio_network_t::multiple_qos_flow_id_instances; + break; + case asn1::ngap::cause_radio_network_opts::options::invalid_qos_combination: + cause = cause_radio_network_t::invalid_qos_combination; + break; + // NGAP + default: + cause = + static_cast(ngap_cause.radio_network().value + NGAP_RADIO_NETWORK_CAUSE_OFFSET); + } break; case asn1::ngap::cause_c::types_opts::transport: // The mapping is not 1:1, so we need to handle some cases separately From bf4c838da348f1082f9d4e12028c956977b3a4f4 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 27 Feb 2024 15:55:20 +0100 Subject: [PATCH 066/140] cu_cp,ngap,f1ap,e1ap: align cause conversion functions --- lib/e1ap/common/e1ap_asn1_converters.h | 6 ++-- lib/e1ap/cu_cp/e1ap_cu_cp_asn1_helpers.h | 28 +++++++++---------- lib/e1ap/cu_cp/e1ap_cu_cp_impl.cpp | 2 +- lib/e1ap/cu_up/e1ap_cu_up_asn1_helpers.h | 6 ++-- lib/e1ap/cu_up/e1ap_cu_up_impl.cpp | 6 ++-- lib/f1ap/cu_cp/f1ap_asn1_converters.h | 7 +++-- lib/f1ap/cu_cp/f1ap_asn1_helpers.h | 4 +-- lib/f1ap/cu_cp/f1ap_cu_impl.cpp | 2 +- .../procedures/ue_context_setup_procedure.cpp | 4 +-- lib/ngap/ngap_asn1_converters.h | 10 +++---- lib/ngap/ngap_asn1_helpers.h | 6 ++-- lib/ngap/ngap_error_indication_helper.h | 2 +- 12 files changed, 42 insertions(+), 41 deletions(-) diff --git a/lib/e1ap/common/e1ap_asn1_converters.h b/lib/e1ap/common/e1ap_asn1_converters.h index 97c07f985a..f141575645 100644 --- a/lib/e1ap/common/e1ap_asn1_converters.h +++ b/lib/e1ap/common/e1ap_asn1_converters.h @@ -969,7 +969,7 @@ inline e1ap_pdcp_config e1ap_asn1_to_pdcp_config(asn1::e1ap::pdcp_cfg_s asn1_pdc /// \brief Convert E1AP Cause to \c cause_t type. /// \param e1ap_cause The E1AP Cause. /// \return The cause type. -inline cause_t e1ap_cause_to_cause(asn1::e1ap::cause_c e1ap_cause) +inline cause_t asn1_to_cause(asn1::e1ap::cause_c e1ap_cause) { cause_t cause; @@ -1086,7 +1086,7 @@ inline cause_t e1ap_cause_to_cause(asn1::e1ap::cause_c e1ap_cause) /// \brief Convert \c cause_t type to E1AP ASN.1 cause. /// \param cause The cause_t type. /// \return The E1AP ASN.1 cause. -inline asn1::e1ap::cause_c cause_to_asn1_cause(cause_t cause) +inline asn1::e1ap::cause_c cause_to_e1ap_asn1(cause_t cause) { asn1::e1ap::cause_c e1ap_cause; @@ -1500,7 +1500,7 @@ inline void e1ap_drb_failed_item_list_to_asn1( // Add DRB ID asn1_drb_failed_item.drb_id = drb_id_to_uint(drb_failed_item.drb_id); // Add Cause - asn1_drb_failed_item.cause = cause_to_asn1_cause(drb_failed_item.cause); + asn1_drb_failed_item.cause = cause_to_e1ap_asn1(drb_failed_item.cause); asn1_drb_item_list.push_back(asn1_drb_failed_item); } } diff --git a/lib/e1ap/cu_cp/e1ap_cu_cp_asn1_helpers.h b/lib/e1ap/cu_cp/e1ap_cu_cp_asn1_helpers.h index f1af2cb9c6..5a5c64f1e2 100644 --- a/lib/e1ap/cu_cp/e1ap_cu_cp_asn1_helpers.h +++ b/lib/e1ap/cu_cp/e1ap_cu_cp_asn1_helpers.h @@ -423,7 +423,7 @@ fill_e1ap_bearer_context_setup_response(e1ap_bearer_context_setup_response& e1ap_qos_flow_failed_item failed_qos_flow_item; failed_qos_flow_item.qos_flow_id = uint_to_qos_flow_id(asn1_failed_qos_flow_item.qos_flow_id); - failed_qos_flow_item.cause = e1ap_cause_to_cause(asn1_failed_qos_flow_item.cause); + failed_qos_flow_item.cause = asn1_to_cause(asn1_failed_qos_flow_item.cause); drb_setup_item.flow_failed_list.emplace(failed_qos_flow_item.qos_flow_id, failed_qos_flow_item); } @@ -447,7 +447,7 @@ fill_e1ap_bearer_context_setup_response(e1ap_bearer_context_setup_response& for (const auto& asn1_drb_failed_item : asn1_res_setup_item.drb_failed_list_ng_ran) { e1ap_drb_failed_item_ng_ran drb_failed_item; drb_failed_item.drb_id = uint_to_drb_id(asn1_drb_failed_item.drb_id); - drb_failed_item.cause = e1ap_cause_to_cause(asn1_drb_failed_item.cause); + drb_failed_item.cause = asn1_to_cause(asn1_drb_failed_item.cause); res_setup_item.drb_failed_list_ng_ran.emplace(drb_failed_item.drb_id, drb_failed_item); } @@ -487,7 +487,7 @@ fill_e1ap_bearer_context_setup_response(e1ap_bearer_context_setup_response& e1ap_pdu_session_resource_failed_item failed_item; failed_item.pdu_session_id = uint_to_pdu_session_id(asn1_failed_item.pdu_session_id); - failed_item.cause = e1ap_cause_to_cause(asn1_failed_item.cause); + failed_item.cause = asn1_to_cause(asn1_failed_item.cause); res.pdu_session_resource_failed_list.emplace(failed_item.pdu_session_id, failed_item); } @@ -500,7 +500,7 @@ fill_e1ap_bearer_context_setup_response(e1ap_bearer_context_setup_response& const asn1::e1ap::bearer_context_setup_fail_s& e1ap_bearer_context_setup_fail) { res.success = false; - res.cause = e1ap_cause_to_cause(e1ap_bearer_context_setup_fail->cause); + res.cause = asn1_to_cause(e1ap_bearer_context_setup_fail->cause); if (e1ap_bearer_context_setup_fail->crit_diagnostics_present) { // TODO: Add crit diagnostics } @@ -695,7 +695,7 @@ inline void fill_e1ap_bearer_context_modification_response( e1ap_qos_flow_failed_item failed_qos_flow_item; failed_qos_flow_item.qos_flow_id = uint_to_qos_flow_id(asn1_failed_qos_flow_item.qos_flow_id); - failed_qos_flow_item.cause = e1ap_cause_to_cause(asn1_failed_qos_flow_item.cause); + failed_qos_flow_item.cause = asn1_to_cause(asn1_failed_qos_flow_item.cause); drb_setup_item.flow_failed_list.emplace(failed_qos_flow_item.qos_flow_id, failed_qos_flow_item); } @@ -721,7 +721,7 @@ inline void fill_e1ap_bearer_context_modification_response( for (const auto& asn1_drb_failed_item : asn1_res_mod_item.drb_failed_mod_list_ng_ran) { e1ap_drb_failed_item_ng_ran drb_failed_item; drb_failed_item.drb_id = uint_to_drb_id(asn1_drb_failed_item.drb_id); - drb_failed_item.cause = e1ap_cause_to_cause(asn1_drb_failed_item.cause); + drb_failed_item.cause = asn1_to_cause(asn1_drb_failed_item.cause); res_mod_item.drb_failed_list_ng_ran.emplace(drb_failed_item.drb_id, drb_failed_item); } @@ -755,7 +755,7 @@ inline void fill_e1ap_bearer_context_modification_response( e1ap_pdu_session_resource_failed_item failed_item; failed_item.pdu_session_id = uint_to_pdu_session_id(asn1_failed_item.pdu_session_id); - failed_item.cause = e1ap_cause_to_cause(asn1_failed_item.cause); + failed_item.cause = asn1_to_cause(asn1_failed_item.cause); res.pdu_session_resource_failed_list.emplace(failed_item.pdu_session_id, failed_item); } @@ -800,7 +800,7 @@ inline void fill_e1ap_bearer_context_modification_response( e1ap_qos_flow_failed_item failed_qos_flow_item; failed_qos_flow_item.qos_flow_id = uint_to_qos_flow_id(asn1_failed_qos_flow_item.qos_flow_id); - failed_qos_flow_item.cause = e1ap_cause_to_cause(asn1_failed_qos_flow_item.cause); + failed_qos_flow_item.cause = asn1_to_cause(asn1_failed_qos_flow_item.cause); drb_setup_item.flow_failed_list.emplace(failed_qos_flow_item.qos_flow_id, failed_qos_flow_item); } @@ -826,7 +826,7 @@ inline void fill_e1ap_bearer_context_modification_response( for (const auto& asn1_drb_failed_item : asn1_res_mod_item.drb_failed_list_ng_ran) { e1ap_drb_failed_item_ng_ran drb_failed_item; drb_failed_item.drb_id = uint_to_drb_id(asn1_drb_failed_item.drb_id); - drb_failed_item.cause = e1ap_cause_to_cause(asn1_drb_failed_item.cause); + drb_failed_item.cause = asn1_to_cause(asn1_drb_failed_item.cause); res_mod_item.drb_failed_list_ng_ran.emplace(drb_failed_item.drb_id, drb_failed_item); } @@ -858,7 +858,7 @@ inline void fill_e1ap_bearer_context_modification_response( e1ap_qos_flow_failed_item failed_qos_flow_item; failed_qos_flow_item.qos_flow_id = uint_to_qos_flow_id(asn1_failed_qos_flow_item.qos_flow_id); - failed_qos_flow_item.cause = e1ap_cause_to_cause(asn1_failed_qos_flow_item.cause); + failed_qos_flow_item.cause = asn1_to_cause(asn1_failed_qos_flow_item.cause); drb_mod_item.flow_failed_list.emplace(failed_qos_flow_item.qos_flow_id, failed_qos_flow_item); } @@ -886,7 +886,7 @@ inline void fill_e1ap_bearer_context_modification_response( for (const auto& asn1_drb_failed_item : asn1_res_mod_item.drb_failed_to_modify_list_ng_ran) { e1ap_drb_failed_item_ng_ran drb_failed_item; drb_failed_item.drb_id = uint_to_drb_id(asn1_drb_failed_item.drb_id); - drb_failed_item.cause = e1ap_cause_to_cause(asn1_drb_failed_item.cause); + drb_failed_item.cause = asn1_to_cause(asn1_drb_failed_item.cause); res_mod_item.drb_failed_to_modify_list_ng_ran.emplace(drb_failed_item.drb_id, drb_failed_item); } @@ -920,7 +920,7 @@ inline void fill_e1ap_bearer_context_modification_response( e1ap_pdu_session_resource_failed_item failed_item; failed_item.pdu_session_id = uint_to_pdu_session_id(asn1_failed_item.pdu_session_id); - failed_item.cause = e1ap_cause_to_cause(asn1_failed_item.cause); + failed_item.cause = asn1_to_cause(asn1_failed_item.cause); res.pdu_session_resource_failed_to_modify_list.emplace(failed_item.pdu_session_id, failed_item); } @@ -934,7 +934,7 @@ inline void fill_e1ap_bearer_context_modification_response( const asn1::e1ap::bearer_context_mod_fail_s& asn1_bearer_context_modification_fail) { res.success = false; - res.cause = e1ap_cause_to_cause(asn1_bearer_context_modification_fail->cause); + res.cause = asn1_to_cause(asn1_bearer_context_modification_fail->cause); if (asn1_bearer_context_modification_fail->crit_diagnostics_present) { // TODO: Add crit diagnostics } @@ -943,7 +943,7 @@ inline void fill_e1ap_bearer_context_modification_response( inline void fill_asn1_bearer_context_release_command(asn1::e1ap::bearer_context_release_cmd_s& asn1_command, const e1ap_bearer_context_release_command& command) { - asn1_command->cause = cause_to_asn1_cause(command.cause); + asn1_command->cause = cause_to_e1ap_asn1(command.cause); } } // namespace srs_cu_cp diff --git a/lib/e1ap/cu_cp/e1ap_cu_cp_impl.cpp b/lib/e1ap/cu_cp/e1ap_cu_cp_impl.cpp index e3827a6130..41148c56c7 100644 --- a/lib/e1ap/cu_cp/e1ap_cu_cp_impl.cpp +++ b/lib/e1ap/cu_cp/e1ap_cu_cp_impl.cpp @@ -64,7 +64,7 @@ void e1ap_cu_cp_impl::handle_cu_up_e1_setup_response(const cu_up_e1_setup_respon e1ap_msg.pdu.unsuccessful_outcome().load_info_obj(ASN1_E1AP_ID_GNB_CU_UP_E1_SETUP); e1ap_msg.pdu.unsuccessful_outcome().value.gnb_cu_up_e1_setup_fail(); auto& setup_fail = e1ap_msg.pdu.unsuccessful_outcome().value.gnb_cu_up_e1_setup_fail(); - setup_fail->cause = cause_to_asn1_cause(msg.cause.value()); + setup_fail->cause = cause_to_e1ap_asn1(msg.cause.value()); // set values handled by E1 setup_fail->transaction_id = current_transaction_id; diff --git a/lib/e1ap/cu_up/e1ap_cu_up_asn1_helpers.h b/lib/e1ap/cu_up/e1ap_cu_up_asn1_helpers.h index 9a0a486116..5948d1e7a7 100644 --- a/lib/e1ap/cu_up/e1ap_cu_up_asn1_helpers.h +++ b/lib/e1ap/cu_up/e1ap_cu_up_asn1_helpers.h @@ -361,7 +361,7 @@ inline void fill_asn1_bearer_context_setup_response(asn1::e1ap::sys_bearer_conte for (const auto& failed_item : response.pdu_session_resource_failed_list) { asn1::e1ap::pdu_session_res_failed_item_s asn1_failed_item; asn1_failed_item.pdu_session_id = pdu_session_id_to_uint(failed_item.pdu_session_id); - asn1_failed_item.cause = cause_to_asn1_cause(failed_item.cause); + asn1_failed_item.cause = cause_to_e1ap_asn1(failed_item.cause); asn1_bearer_context_setup_response.pdu_session_res_failed_list.push_back(asn1_failed_item); } @@ -724,7 +724,7 @@ inline void fill_asn1_bearer_context_modification_response(asn1::e1ap::sys_beare for (const auto& res_failed_mod_item : response.pdu_session_resource_failed_list) { asn1::e1ap::pdu_session_res_failed_mod_item_s asn1_res_failed_mod_item; asn1_res_failed_mod_item.pdu_session_id = pdu_session_id_to_uint(res_failed_mod_item.pdu_session_id); - asn1_res_failed_mod_item.cause = cause_to_asn1_cause(res_failed_mod_item.cause); + asn1_res_failed_mod_item.cause = cause_to_e1ap_asn1(res_failed_mod_item.cause); asn1_bearer_context_modification_response.pdu_session_res_failed_mod_list.push_back(asn1_res_failed_mod_item); } @@ -847,7 +847,7 @@ inline void fill_asn1_bearer_context_modification_response(asn1::e1ap::sys_beare for (const auto& res_failed_to_modify_item : response.pdu_session_resource_failed_to_modify_list) { asn1::e1ap::pdu_session_res_failed_to_modify_item_s asn1_res_failed_to_modify_item; asn1_res_failed_to_modify_item.pdu_session_id = pdu_session_id_to_uint(res_failed_to_modify_item.pdu_session_id); - asn1_res_failed_to_modify_item.cause = cause_to_asn1_cause(res_failed_to_modify_item.cause); + asn1_res_failed_to_modify_item.cause = cause_to_e1ap_asn1(res_failed_to_modify_item.cause); asn1_bearer_context_modification_response.pdu_session_res_failed_to_modify_list.push_back( asn1_res_failed_to_modify_item); diff --git a/lib/e1ap/cu_up/e1ap_cu_up_impl.cpp b/lib/e1ap/cu_up/e1ap_cu_up_impl.cpp index b220d2d1a7..33d19a7e04 100644 --- a/lib/e1ap/cu_up/e1ap_cu_up_impl.cpp +++ b/lib/e1ap/cu_up/e1ap_cu_up_impl.cpp @@ -240,7 +240,7 @@ void e1ap_cu_up_impl::handle_bearer_context_setup_request(const asn1::e1ap::bear connection_handler.on_new_message(e1ap_msg); } else { e1ap_msg.pdu.unsuccessful_outcome().value.bearer_context_setup_fail()->cause = - cause_to_asn1_cause(bearer_context_setup_response_msg.cause.value()); + cause_to_e1ap_asn1(bearer_context_setup_response_msg.cause.value()); // send response ue_ctxt.logger.log_debug("Sending BearerContextSetupFailure"); @@ -311,7 +311,7 @@ void e1ap_cu_up_impl::handle_bearer_context_modification_request(const asn1::e1a connection_handler.on_new_message(e1ap_msg); } else { e1ap_msg.pdu.unsuccessful_outcome().value.bearer_context_mod_fail()->cause = - cause_to_asn1_cause(bearer_context_mod_response_msg.cause.value()); + cause_to_e1ap_asn1(bearer_context_mod_response_msg.cause.value()); // send response ue_ctxt.logger.log_debug("Sending BearerContextModificationFailure"); @@ -331,7 +331,7 @@ void e1ap_cu_up_impl::handle_bearer_context_release_command(const asn1::e1ap::be e1ap_ue_context& ue_ctxt = ue_ctxt_list[int_to_gnb_cu_up_ue_e1ap_id(msg->gnb_cu_up_ue_e1ap_id)]; bearer_context_release_cmd.ue_index = ue_ctxt.ue_ids.ue_index; - bearer_context_release_cmd.cause = e1ap_cause_to_cause(msg->cause); + bearer_context_release_cmd.cause = asn1_to_cause(msg->cause); // Forward message to CU-UP cu_up_notifier.on_bearer_context_release_command_received(bearer_context_release_cmd); diff --git a/lib/f1ap/cu_cp/f1ap_asn1_converters.h b/lib/f1ap/cu_cp/f1ap_asn1_converters.h index 005f0af4e7..96b0a48149 100644 --- a/lib/f1ap/cu_cp/f1ap_asn1_converters.h +++ b/lib/f1ap/cu_cp/f1ap_asn1_converters.h @@ -27,7 +27,7 @@ namespace srs_cu_cp { /// \brief Convert F1AP ASN.1 Cause to \c cause_t type. /// \param f1ap_cause The F1AP Cause. /// \return The cause_t type. -inline cause_t f1ap_asn1_to_cause(asn1::f1ap::cause_c f1ap_cause) +inline cause_t asn1_to_cause(asn1::f1ap::cause_c f1ap_cause) { cause_t cause; @@ -128,6 +128,7 @@ inline cause_t f1ap_asn1_to_cause(asn1::f1ap::cause_c f1ap_cause) inline asn1::f1ap::cause_c cause_to_f1ap_asn1(cause_t cause) { asn1::f1ap::cause_c f1ap_cause; + if (variant_holds_alternative(cause)) { // Convert F1AP types if (static_cast(variant_get(cause)) >= F1AP_RADIO_NETWORK_CAUSE_OFFSET && @@ -869,7 +870,7 @@ asn1_to_f1ap_srbs_failed_to_be_setup_mod_item(const template_asn1_item& asn1_srb // srb id srbs_failed_to_be_setup_mod_item.srb_id = int_to_srb_id(asn1_srbs_failed_to_be_setup_mod_item.srb_id); if (asn1_srbs_failed_to_be_setup_mod_item.cause_present) { - srbs_failed_to_be_setup_mod_item.cause = f1ap_asn1_to_cause(asn1_srbs_failed_to_be_setup_mod_item.cause); + srbs_failed_to_be_setup_mod_item.cause = asn1_to_cause(asn1_srbs_failed_to_be_setup_mod_item.cause); } return srbs_failed_to_be_setup_mod_item; @@ -887,7 +888,7 @@ asn1_to_f1ap_drbs_failed_to_be_setup_mod_item(const template_asn1_item& asn1_drb // drb id drbs_failed_to_be_setup_mod_item.drb_id = uint_to_drb_id(asn1_drbs_failed_to_be_setup_mod_item.drb_id); if (asn1_drbs_failed_to_be_setup_mod_item.cause_present) { - drbs_failed_to_be_setup_mod_item.cause = f1ap_asn1_to_cause(asn1_drbs_failed_to_be_setup_mod_item.cause); + drbs_failed_to_be_setup_mod_item.cause = asn1_to_cause(asn1_drbs_failed_to_be_setup_mod_item.cause); } return drbs_failed_to_be_setup_mod_item; diff --git a/lib/f1ap/cu_cp/f1ap_asn1_helpers.h b/lib/f1ap/cu_cp/f1ap_asn1_helpers.h index 4bed4daf55..b240fe27af 100644 --- a/lib/f1ap/cu_cp/f1ap_asn1_helpers.h +++ b/lib/f1ap/cu_cp/f1ap_asn1_helpers.h @@ -381,7 +381,7 @@ inline void fill_f1ap_ue_context_modification_response(f1ap_ue_context_modificat f1ap_scell_failed_to_setup_mod_item scell_failed_item; scell_failed_item.scell_id = cgi_from_asn1(asn1_scell_failed_item.scell_id); if (asn1_scell_failed_item.cause_present) { - scell_failed_item.cause = f1ap_asn1_to_cause(asn1_scell_failed_item.cause); + scell_failed_item.cause = asn1_to_cause(asn1_scell_failed_item.cause); } res.scell_failed_to_setup_mod_list.push_back(scell_failed_item); } @@ -456,7 +456,7 @@ inline void fill_f1ap_ue_context_modification_response(f1ap_ue_context_modificat const asn1::f1ap::ue_context_mod_fail_s& asn1_fail) { res.success = false; - res.cause = f1ap_asn1_to_cause(asn1_fail->cause); + res.cause = asn1_to_cause(asn1_fail->cause); if (asn1_fail->crit_diagnostics_present) { // TODO: Add crit diagnostics } diff --git a/lib/f1ap/cu_cp/f1ap_cu_impl.cpp b/lib/f1ap/cu_cp/f1ap_cu_impl.cpp index c944a7507f..b85788c226 100644 --- a/lib/f1ap/cu_cp/f1ap_cu_impl.cpp +++ b/lib/f1ap/cu_cp/f1ap_cu_impl.cpp @@ -351,7 +351,7 @@ void f1ap_cu_impl::handle_ue_context_release_request(const asn1::f1ap::ue_contex f1ap_ue_context_release_request req; req.ue_index = ue_ctxt.ue_ids.ue_index; - req.cause = f1ap_asn1_to_cause(msg->cause); + req.cause = asn1_to_cause(msg->cause); du_processor_notifier.on_du_initiated_ue_context_release_request(req); } diff --git a/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp b/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp index e326537f31..c0b805b08c 100644 --- a/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp +++ b/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp @@ -392,7 +392,7 @@ static void fill_f1ap_ue_context_setup_response(f1ap_ue_context_setup_response& response.ue_index = ue_index; // cause - response.cause = f1ap_asn1_to_cause(asn1_failure->cause); + response.cause = asn1_to_cause(asn1_failure->cause); // potential sp cell list if (asn1_failure->potential_sp_cell_list_present) { @@ -481,7 +481,7 @@ static void fill_f1ap_ue_context_setup_response(f1ap_ue_context_setup_response& // cause if (asn1_scell_failed_to_setup_item->scell_failedto_setup_item().cause_present) { scell_failed_to_setup_item.cause = - f1ap_asn1_to_cause(asn1_scell_failed_to_setup_item->scell_failedto_setup_item().cause); + asn1_to_cause(asn1_scell_failed_to_setup_item->scell_failedto_setup_item().cause); } response.scell_failed_to_setup_list.push_back(scell_failed_to_setup_item); diff --git a/lib/ngap/ngap_asn1_converters.h b/lib/ngap/ngap_asn1_converters.h index 6be41fdb14..215bbef231 100644 --- a/lib/ngap/ngap_asn1_converters.h +++ b/lib/ngap/ngap_asn1_converters.h @@ -112,7 +112,7 @@ cu_cp_qos_flow_per_tnl_info_to_ngap_qos_flow_per_tnl_info(const cu_cp_qos_flow_p /// \brief Convert \c cause_t type to NGAP cause. /// \param cause The cause_t type. /// \return The NGAP cause. -inline asn1::ngap::cause_c cause_to_asn1(cause_t cause) +inline asn1::ngap::cause_c cause_to_ngap_asn1(cause_t cause) { asn1::ngap::cause_c ngap_cause; @@ -277,7 +277,7 @@ inline asn1::ngap::qos_flow_with_cause_item_s cu_cp_qos_flow_failed_to_setup_ite { asn1::ngap::qos_flow_with_cause_item_s asn1_failed_item; asn1_failed_item.qos_flow_id = qos_flow_id_to_uint(cu_cp_failed_item.qos_flow_id); - asn1_failed_item.cause = cause_to_asn1(cu_cp_failed_item.cause); + asn1_failed_item.cause = cause_to_ngap_asn1(cu_cp_failed_item.cause); return asn1_failed_item; } @@ -444,7 +444,7 @@ inline bool pdu_session_res_failed_to_modify_item_to_asn1(template_asn1_item& as asn1_resp.pdu_session_id = pdu_session_id_to_uint(resp.pdu_session_id); asn1::ngap::pdu_session_res_modify_unsuccessful_transfer_s response_transfer; - response_transfer.cause = cause_to_asn1(resp.unsuccessful_transfer.cause); + response_transfer.cause = cause_to_ngap_asn1(resp.unsuccessful_transfer.cause); // Pack transfer byte_buffer pdu = pack_into_pdu(response_transfer); @@ -468,7 +468,7 @@ inline bool pdu_session_res_setup_failed_item_to_asn1(template_asn1_item& asn1_resp.pdu_session_id = pdu_session_id_to_uint(resp.pdu_session_id); asn1::ngap::pdu_session_res_setup_unsuccessful_transfer_s setup_unsuccessful_transfer; - setup_unsuccessful_transfer.cause = cause_to_asn1(resp.unsuccessful_transfer.cause); + setup_unsuccessful_transfer.cause = cause_to_ngap_asn1(resp.unsuccessful_transfer.cause); // TODO: Add crit diagnostics @@ -901,7 +901,7 @@ inline bool pdu_session_res_failed_to_setup_item_ho_ack_to_asn1( asn1::ngap::ho_res_alloc_unsuccessful_transfer_s asn1_ho_res_alloc_unsuccessful_transfer; // cause - asn1_ho_res_alloc_unsuccessful_transfer.cause = cause_to_asn1(failed_item.unsuccessful_transfer.cause); + asn1_ho_res_alloc_unsuccessful_transfer.cause = cause_to_ngap_asn1(failed_item.unsuccessful_transfer.cause); // crit diagnostics if (failed_item.unsuccessful_transfer.crit_diagnostics.has_value()) { diff --git a/lib/ngap/ngap_asn1_helpers.h b/lib/ngap/ngap_asn1_helpers.h index 9ff673253c..6136826050 100644 --- a/lib/ngap/ngap_asn1_helpers.h +++ b/lib/ngap/ngap_asn1_helpers.h @@ -492,7 +492,7 @@ inline void fill_asn1_initial_context_setup_failure(asn1::ngap::init_context_set const ngap_init_context_setup_failure& fail) { // Fill cause - asn1_fail->cause = cause_to_asn1(fail.cause); + asn1_fail->cause = cause_to_ngap_asn1(fail.cause); // Fill PDU Session Resource Failed to Setup List if (!fail.pdu_session_res_failed_to_setup_items.empty()) { @@ -702,7 +702,7 @@ inline void fill_asn1_ue_context_release_request(asn1::ngap::ue_context_release_ } } - asn1_msg->cause = cause_to_asn1(msg.cause); + asn1_msg->cause = cause_to_ngap_asn1(msg.cause); } /// \brief Convert NGAP ASN1 PDU Session Resource Release Command ASN1 struct to common type. @@ -1167,7 +1167,7 @@ fill_asn1_handover_resource_allocation_response(asn1::ngap::ho_fail_s& { if (!ho_response.success) { // cause - asn1_ho_failure->cause = cause_to_asn1(ho_response.cause); + asn1_ho_failure->cause = cause_to_ngap_asn1(ho_response.cause); // crit diagnostics if (ho_response.crit_diagnostics.has_value()) { diff --git a/lib/ngap/ngap_error_indication_helper.h b/lib/ngap/ngap_error_indication_helper.h index 0a3f9c9a9b..5dab2bdc6c 100644 --- a/lib/ngap/ngap_error_indication_helper.h +++ b/lib/ngap/ngap_error_indication_helper.h @@ -51,7 +51,7 @@ inline void send_error_indication(ngap_message_notifier& ngap_notifier, if (cause.has_value()) { error_ind->cause_present = true; - error_ind->cause = cause_to_asn1(cause.value()); + error_ind->cause = cause_to_ngap_asn1(cause.value()); } // TODO: Add missing values From 2e100bfa90ada09eb4b00a2e401e25ff7f00af73 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 27 Feb 2024 16:34:59 +0100 Subject: [PATCH 067/140] cu_cp: add cause conversion unittest --- tests/unittests/asn1/CMakeLists.txt | 6 + .../asn1/asn1_cause_conversion_test.cpp | 399 ++++++++++++++++++ 2 files changed, 405 insertions(+) create mode 100644 tests/unittests/asn1/asn1_cause_conversion_test.cpp diff --git a/tests/unittests/asn1/CMakeLists.txt b/tests/unittests/asn1/CMakeLists.txt index 841bb95fed..9e507c54ac 100644 --- a/tests/unittests/asn1/CMakeLists.txt +++ b/tests/unittests/asn1/CMakeLists.txt @@ -6,6 +6,8 @@ # the distribution. # +include_directories(../../..) + set_directory_properties(PROPERTIES LABELS "asn1") add_executable(asn1_utils_test asn1_utils_test.cpp) @@ -34,3 +36,7 @@ gtest_discover_tests(asn1_f1ap_test) add_executable(asn1_ngap_test asn1_ngap_test.cpp) target_link_libraries(asn1_ngap_test ngap_asn1 srslog srsran_support srsran_pcap gtest gtest_main) gtest_discover_tests(asn1_ngap_test) + +add_executable(asn1_cause_conversion_test asn1_cause_conversion_test.cpp) +target_link_libraries(asn1_cause_conversion_test ngap_asn1 f1ap_asn1 e1ap_asn1 srslog srsran_support gtest gtest_main) +gtest_discover_tests(asn1_cause_conversion_test) diff --git a/tests/unittests/asn1/asn1_cause_conversion_test.cpp b/tests/unittests/asn1/asn1_cause_conversion_test.cpp new file mode 100644 index 0000000000..3bed74ac6f --- /dev/null +++ b/tests/unittests/asn1/asn1_cause_conversion_test.cpp @@ -0,0 +1,399 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "lib/e1ap/common/e1ap_asn1_converters.h" +#include "lib/f1ap/cu_cp/f1ap_asn1_converters.h" +#include "lib/ngap/ngap_asn1_converters.h" +#include + +using namespace srsran; +using namespace srs_cu_cp; + +class asn1_cause_conversion_test : public ::testing::Test +{ +public: + ~asn1_cause_conversion_test() override + { + // flush logger after each test + srslog::flush(); + } + +protected: + asn1_cause_conversion_test() + { + srslog::fetch_basic_logger("ASN1").set_level(srslog::basic_levels::debug); + srslog::fetch_basic_logger("ASN1").set_hex_dump_max_size(-1); + + test_logger.set_level(srslog::basic_levels::debug); + test_logger.set_hex_dump_max_size(-1); + + // Start the log backend. + srslog::init(); + } + + srslog::basic_logger& test_logger = srslog::fetch_basic_logger("TEST"); +}; + +// test conversion from ngap asn1 +TEST_F(asn1_cause_conversion_test, when_ngap_cause_received_then_conversion_to_common_cause_successful) +{ + asn1::ngap::cause_c ngap_cause; + cause_t cause; + + ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::unspecified; + cause = asn1_to_cause(ngap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_radio_network_t::unspecified); + + ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::cell_not_available; + cause = asn1_to_cause(ngap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_radio_network_t::cell_not_available); + + ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::up_confidentiality_protection_not_possible; + cause = asn1_to_cause(ngap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), + cause_radio_network_t::up_confidentiality_protection_not_possible); + + ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::ho_target_not_allowed; + cause = asn1_to_cause(ngap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_radio_network_t::ho_target_not_allowed); + + ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::user_inactivity; + cause = asn1_to_cause(ngap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_radio_network_t::user_inactivity); + + ngap_cause.set_transport() = asn1::ngap::cause_transport_opts::unspecified; + cause = asn1_to_cause(ngap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_transport_t::unspecified); + + ngap_cause.set_nas() = asn1::ngap::cause_nas_opts::deregister; + cause = asn1_to_cause(ngap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_nas_t::deregister); + + ngap_cause.set_protocol() = asn1::ngap::cause_protocol_opts::msg_not_compatible_with_receiver_state; + cause = asn1_to_cause(ngap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_protocol_t::msg_not_compatible_with_receiver_state); + + ngap_cause.set_misc() = asn1::ngap::cause_misc_opts::unspecified; + cause = asn1_to_cause(ngap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_misc_t::unspecified); + + ngap_cause.set_misc() = asn1::ngap::cause_misc_opts::unknown_plmn_or_sn_pn; + cause = asn1_to_cause(ngap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_misc_t::unknown_plmn_or_sn_pn); +} + +// test conversion to ngap asn1 +TEST_F(asn1_cause_conversion_test, when_common_cause_received_then_conversion_to_ngap_cause_successful) +{ + cause_t cause; + asn1::ngap::cause_c ngap_cause; + + cause = cause_radio_network_t::unspecified; + ngap_cause = cause_to_ngap_asn1(cause); + ASSERT_EQ(ngap_cause.type(), asn1::ngap::cause_c::types::radio_network); + ASSERT_EQ(ngap_cause.radio_network().value, asn1::ngap::cause_radio_network_opts::unspecified); + + cause = cause_radio_network_t::unknown_local_ue_ngap_id; + ngap_cause = cause_to_ngap_asn1(cause); + ASSERT_EQ(ngap_cause.type(), asn1::ngap::cause_c::types::radio_network); + ASSERT_EQ(ngap_cause.radio_network().value, asn1::ngap::cause_radio_network_opts::unknown_local_ue_ngap_id); + + cause = cause_radio_network_t::ue_in_rrc_inactive_state_not_reachable; + ngap_cause = cause_to_ngap_asn1(cause); + ASSERT_EQ(ngap_cause.type(), asn1::ngap::cause_c::types::radio_network); + ASSERT_EQ(ngap_cause.radio_network().value, + asn1::ngap::cause_radio_network_opts::ue_in_rrc_inactive_state_not_reachable); + + cause = cause_radio_network_t::encryption_algorithms_not_supported; + ngap_cause = cause_to_ngap_asn1(cause); + ASSERT_EQ(ngap_cause.type(), asn1::ngap::cause_c::types::radio_network); + ASSERT_EQ(ngap_cause.radio_network().value, + asn1::ngap::cause_radio_network_opts::encryption_and_or_integrity_protection_algorithms_not_supported); + + cause = cause_radio_network_t::rl_fail_rlc; + ngap_cause = cause_to_ngap_asn1(cause); + ASSERT_EQ(ngap_cause.type(), asn1::ngap::cause_c::types::radio_network); + ASSERT_EQ(ngap_cause.radio_network().value, asn1::ngap::cause_radio_network_opts::radio_conn_with_ue_lost); + + cause = cause_transport_t::unspecified; + ngap_cause = cause_to_ngap_asn1(cause); + ASSERT_EQ(ngap_cause.type(), asn1::ngap::cause_c::types::transport); + ASSERT_EQ(ngap_cause.transport().value, asn1::ngap::cause_transport_opts::unspecified); + + cause = cause_nas_t::deregister; + ngap_cause = cause_to_ngap_asn1(cause); + ASSERT_EQ(ngap_cause.type(), asn1::ngap::cause_c::types::nas); + ASSERT_EQ(ngap_cause.nas().value, asn1::ngap::cause_nas_opts::deregister); + + cause = cause_protocol_t::msg_not_compatible_with_receiver_state; + ngap_cause = cause_to_ngap_asn1(cause); + ASSERT_EQ(ngap_cause.type(), asn1::ngap::cause_c::types::protocol); + ASSERT_EQ(ngap_cause.protocol().value, asn1::ngap::cause_protocol_opts::msg_not_compatible_with_receiver_state); + + cause = cause_misc_t::unspecified; + ngap_cause = cause_to_ngap_asn1(cause); + ASSERT_EQ(ngap_cause.type(), asn1::ngap::cause_c::types::misc); + ASSERT_EQ(ngap_cause.misc().value, asn1::ngap::cause_misc_opts::unspecified); + + cause = cause_misc_t::unknown_plmn_or_sn_pn; + ngap_cause = cause_to_ngap_asn1(cause); + ASSERT_EQ(ngap_cause.type(), asn1::ngap::cause_c::types::misc); + ASSERT_EQ(ngap_cause.misc().value, asn1::ngap::cause_misc_opts::unknown_plmn_or_sn_pn); +} + +// test conversion from f1ap asn1 +TEST_F(asn1_cause_conversion_test, when_f1ap_cause_received_then_conversion_to_common_cause_successful) +{ + asn1::f1ap::cause_c f1ap_cause; + cause_t cause; + + f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::unspecified; + cause = asn1_to_cause(f1ap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_radio_network_t::unspecified); + + f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::cell_not_available; + cause = asn1_to_cause(f1ap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_radio_network_t::cell_not_available); + + f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::normal_release; + cause = asn1_to_cause(f1ap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_radio_network_t::normal_release); + + f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::gnb_cu_cell_capacity_exceeded; + cause = asn1_to_cause(f1ap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_radio_network_t::gnb_cu_cell_capacity_exceeded); + + f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::rl_fail_others; + cause = asn1_to_cause(f1ap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_radio_network_t::rl_fail_others); + + f1ap_cause.set_transport() = asn1::f1ap::cause_transport_opts::unspecified; + cause = asn1_to_cause(f1ap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_transport_t::unspecified); + + f1ap_cause.set_transport() = asn1::f1ap::cause_transport_opts::unknown_tnl_address_for_iab; + cause = asn1_to_cause(f1ap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_transport_t::unknown_tnl_address_for_iab); + + f1ap_cause.set_transport() = asn1::f1ap::cause_transport_opts::unknown_up_tnl_info_for_iab; + cause = asn1_to_cause(f1ap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_transport_t::unknown_up_tnl_info_for_iab); + + f1ap_cause.set_protocol() = asn1::f1ap::cause_protocol_opts::semantic_error; + cause = asn1_to_cause(f1ap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_protocol_t::semantic_error); + + f1ap_cause.set_misc() = asn1::f1ap::cause_misc_opts::hardware_fail; + cause = asn1_to_cause(f1ap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_misc_t::hardware_fail); + + f1ap_cause.set_misc() = asn1::f1ap::cause_misc_opts::unspecified; + cause = asn1_to_cause(f1ap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_misc_t::unspecified); +} + +// test conversion to f1ap asn1 +TEST_F(asn1_cause_conversion_test, when_common_cause_received_then_conversion_to_f1ap_cause_successful) +{ + cause_t cause; + asn1::f1ap::cause_c f1ap_cause; + + cause = cause_radio_network_t::unspecified; + f1ap_cause = cause_to_f1ap_asn1(cause); + ASSERT_EQ(f1ap_cause.type(), asn1::f1ap::cause_c::types::radio_network); + ASSERT_EQ(f1ap_cause.radio_network().value, asn1::f1ap::cause_radio_network_opts::unspecified); + + cause = cause_radio_network_t::cell_not_available; + f1ap_cause = cause_to_f1ap_asn1(cause); + ASSERT_EQ(f1ap_cause.type(), asn1::f1ap::cause_c::types::radio_network); + ASSERT_EQ(f1ap_cause.radio_network().value, asn1::f1ap::cause_radio_network_opts::cell_not_available); + + cause = cause_radio_network_t::normal_release; + f1ap_cause = cause_to_f1ap_asn1(cause); + ASSERT_EQ(f1ap_cause.type(), asn1::f1ap::cause_c::types::radio_network); + ASSERT_EQ(f1ap_cause.radio_network().value, asn1::f1ap::cause_radio_network_opts::normal_release); + + cause = cause_radio_network_t::gnb_cu_cell_capacity_exceeded; + f1ap_cause = cause_to_f1ap_asn1(cause); + ASSERT_EQ(f1ap_cause.type(), asn1::f1ap::cause_c::types::radio_network); + ASSERT_EQ(f1ap_cause.radio_network().value, asn1::f1ap::cause_radio_network_opts::gnb_cu_cell_capacity_exceeded); + + cause = cause_radio_network_t::rl_fail_others; + f1ap_cause = cause_to_f1ap_asn1(cause); + ASSERT_EQ(f1ap_cause.type(), asn1::f1ap::cause_c::types::radio_network); + ASSERT_EQ(f1ap_cause.radio_network().value, asn1::f1ap::cause_radio_network_opts::rl_fail_others); + + cause = cause_transport_t::unspecified; + f1ap_cause = cause_to_f1ap_asn1(cause); + ASSERT_EQ(f1ap_cause.type(), asn1::f1ap::cause_c::types::transport); + ASSERT_EQ(f1ap_cause.transport().value, asn1::f1ap::cause_transport_opts::unspecified); + + cause = cause_transport_t::unknown_tnl_address_for_iab; + f1ap_cause = cause_to_f1ap_asn1(cause); + ASSERT_EQ(f1ap_cause.type(), asn1::f1ap::cause_c::types::transport); + ASSERT_EQ(f1ap_cause.transport().value, asn1::f1ap::cause_transport_opts::unknown_tnl_address_for_iab); + + cause = cause_transport_t::unknown_up_tnl_info_for_iab; + f1ap_cause = cause_to_f1ap_asn1(cause); + ASSERT_EQ(f1ap_cause.type(), asn1::f1ap::cause_c::types::transport); + ASSERT_EQ(f1ap_cause.transport().value, asn1::f1ap::cause_transport_opts::unknown_up_tnl_info_for_iab); + + cause = cause_protocol_t::semantic_error; + f1ap_cause = cause_to_f1ap_asn1(cause); + ASSERT_EQ(f1ap_cause.type(), asn1::f1ap::cause_c::types::protocol); + ASSERT_EQ(f1ap_cause.protocol().value, asn1::f1ap::cause_protocol_opts::semantic_error); + + cause = cause_misc_t::hardware_fail; + f1ap_cause = cause_to_f1ap_asn1(cause); + ASSERT_EQ(f1ap_cause.type(), asn1::f1ap::cause_c::types::misc); + ASSERT_EQ(f1ap_cause.misc().value, asn1::f1ap::cause_misc_opts::hardware_fail); + + cause = cause_misc_t::unspecified; + f1ap_cause = cause_to_f1ap_asn1(cause); + ASSERT_EQ(f1ap_cause.type(), asn1::f1ap::cause_c::types::misc); + ASSERT_EQ(f1ap_cause.misc().value, asn1::f1ap::cause_misc_opts::unspecified); +} + +// test conversion from e1ap asn1 +TEST_F(asn1_cause_conversion_test, when_e1ap_cause_received_then_conversion_to_common_cause_successful) +{ + asn1::e1ap::cause_c e1ap_cause; + cause_t cause; + + e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::unspecified; + cause = asn1_to_cause(e1ap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_radio_network_t::unspecified); + + e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::unknown_or_inconsistent_pair_of_ue_e1ap_id; + cause = asn1_to_cause(e1ap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), + cause_radio_network_t::unknown_or_inconsistent_pair_of_ue_e1ap_id); + + e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::normal_release; + cause = asn1_to_cause(e1ap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_radio_network_t::normal_release); + + e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::pdcp_cfg_not_supported; + cause = asn1_to_cause(e1ap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_radio_network_t::pdcp_cfg_not_supported); + + e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::report_characteristic_empty; + cause = asn1_to_cause(e1ap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_radio_network_t::report_characteristic_empty); + + e1ap_cause.set_transport() = asn1::e1ap::cause_transport_opts::unspecified; + cause = asn1_to_cause(e1ap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_transport_t::unspecified); + + e1ap_cause.set_transport() = asn1::e1ap::cause_transport_opts::unknown_tnl_address_for_iab; + cause = asn1_to_cause(e1ap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_transport_t::unknown_tnl_address_for_iab); + + e1ap_cause.set_protocol() = asn1::e1ap::cause_protocol_opts::semantic_error; + cause = asn1_to_cause(e1ap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_protocol_t::semantic_error); + + e1ap_cause.set_misc() = asn1::e1ap::cause_misc_opts::hardware_fail; + cause = asn1_to_cause(e1ap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_misc_t::hardware_fail); + + e1ap_cause.set_misc() = asn1::e1ap::cause_misc_opts::unspecified; + cause = asn1_to_cause(e1ap_cause); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), cause_misc_t::unspecified); +} + +// test conversion to e1ap asn1 +TEST_F(asn1_cause_conversion_test, when_common_cause_received_then_conversion_to_e1ap_cause_successful) +{ + cause_t cause; + asn1::e1ap::cause_c e1ap_cause; + + cause = cause_radio_network_t::unspecified; + e1ap_cause = cause_to_e1ap_asn1(cause); + ASSERT_EQ(e1ap_cause.type(), asn1::e1ap::cause_c::types::radio_network); + ASSERT_EQ(e1ap_cause.radio_network().value, asn1::e1ap::cause_radio_network_opts::unspecified); + + cause = cause_radio_network_t::unknown_or_inconsistent_pair_of_ue_e1ap_id; + e1ap_cause = cause_to_e1ap_asn1(cause); + ASSERT_EQ(e1ap_cause.type(), asn1::e1ap::cause_c::types::radio_network); + ASSERT_EQ(e1ap_cause.radio_network().value, + asn1::e1ap::cause_radio_network_opts::unknown_or_inconsistent_pair_of_ue_e1ap_id); + + cause = cause_radio_network_t::normal_release; + e1ap_cause = cause_to_e1ap_asn1(cause); + ASSERT_EQ(e1ap_cause.type(), asn1::e1ap::cause_c::types::radio_network); + ASSERT_EQ(e1ap_cause.radio_network().value, asn1::e1ap::cause_radio_network_opts::normal_release); + + cause = cause_radio_network_t::pdcp_cfg_not_supported; + e1ap_cause = cause_to_e1ap_asn1(cause); + ASSERT_EQ(e1ap_cause.type(), asn1::e1ap::cause_c::types::radio_network); + ASSERT_EQ(e1ap_cause.radio_network().value, asn1::e1ap::cause_radio_network_opts::pdcp_cfg_not_supported); + + cause = cause_radio_network_t::report_characteristic_empty; + e1ap_cause = cause_to_e1ap_asn1(cause); + ASSERT_EQ(e1ap_cause.type(), asn1::e1ap::cause_c::types::radio_network); + ASSERT_EQ(e1ap_cause.radio_network().value, asn1::e1ap::cause_radio_network_opts::report_characteristic_empty); + + cause = cause_transport_t::unspecified; + e1ap_cause = cause_to_e1ap_asn1(cause); + ASSERT_EQ(e1ap_cause.type(), asn1::e1ap::cause_c::types::transport); + ASSERT_EQ(e1ap_cause.transport().value, asn1::e1ap::cause_transport_opts::unspecified); + + cause = cause_transport_t::unknown_tnl_address_for_iab; + e1ap_cause = cause_to_e1ap_asn1(cause); + ASSERT_EQ(e1ap_cause.type(), asn1::e1ap::cause_c::types::transport); + ASSERT_EQ(e1ap_cause.transport().value, asn1::e1ap::cause_transport_opts::unknown_tnl_address_for_iab); + + cause = cause_protocol_t::semantic_error; + e1ap_cause = cause_to_e1ap_asn1(cause); + ASSERT_EQ(e1ap_cause.type(), asn1::e1ap::cause_c::types::protocol); + ASSERT_EQ(e1ap_cause.protocol().value, asn1::e1ap::cause_protocol_opts::semantic_error); + + cause = cause_misc_t::hardware_fail; + e1ap_cause = cause_to_e1ap_asn1(cause); + ASSERT_EQ(e1ap_cause.type(), asn1::e1ap::cause_c::types::misc); + ASSERT_EQ(e1ap_cause.misc().value, asn1::e1ap::cause_misc_opts::hardware_fail); + + cause = cause_misc_t::unspecified; + e1ap_cause = cause_to_e1ap_asn1(cause); + ASSERT_EQ(e1ap_cause.type(), asn1::e1ap::cause_c::types::misc); + ASSERT_EQ(e1ap_cause.misc().value, asn1::e1ap::cause_misc_opts::unspecified); +} From b670c3c035d885e3321dc45cd7248446d2e11c29 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Wed, 28 Feb 2024 15:05:18 +0100 Subject: [PATCH 068/140] cu_cp,cu_up: split causes by layer --- include/srsran/cu_cp/cu_cp_types.h | 14 +- .../srsran/e1ap/common/e1_setup_messages.h | 4 +- include/srsran/e1ap/common/e1ap_types.h | 10 +- .../cu_cp/e1ap_cu_cp_bearer_context_update.h | 8 +- .../cu_up/e1ap_cu_up_bearer_context_update.h | 8 +- include/srsran/f1ap/cu_cp/du_setup_notifier.h | 6 +- include/srsran/f1ap/cu_cp/f1ap_cu.h | 2 +- .../f1ap/cu_cp/f1ap_cu_ue_context_update.h | 22 +- include/srsran/ngap/ngap_handover.h | 14 +- include/srsran/ngap/ngap_init_context_setup.h | 2 +- include/srsran/ngap/ngap_setup.h | 2 +- include/srsran/ran/cause.h | 206 ------------ include/srsran/ran/cause/common.h | 50 +++ include/srsran/ran/cause/e1ap_cause.h | 88 ++++++ .../srsran/ran/cause/e1ap_cause_converters.h | 21 ++ include/srsran/ran/cause/f1ap_cause.h | 100 ++++++ .../srsran/ran/cause/f1ap_cause_converters.h | 21 ++ include/srsran/ran/cause/ngap_cause.h | 128 ++++++++ .../srsran/ran/cause/ngap_cause_converters.h | 25 ++ include/srsran/rrc/rrc_ue.h | 4 +- lib/cu_cp/CMakeLists.txt | 2 +- .../cu_up_processor/cu_up_processor_impl.cpp | 2 +- .../cu_up_processor/cu_up_processor_impl.h | 2 +- lib/cu_cp/du_processor/du_processor_impl.cpp | 18 +- lib/cu_cp/du_processor/du_processor_impl.h | 2 +- .../inter_cu_handover_target_routine.cpp | 4 +- .../mobility/inter_du_handover_routine.cpp | 4 +- ..._session_resource_modification_routine.cpp | 6 +- .../pdu_session_resource_release_routine.cpp | 4 +- .../pdu_session_resource_setup_routine.cpp | 7 +- .../routines/pdu_session_routine_helpers.cpp | 3 +- ...blishment_context_modification_routine.cpp | 4 - ...tablishment_context_modification_routine.h | 3 - .../routines/ue_context_release_routine.cpp | 7 +- lib/cu_up/cu_up_impl.cpp | 2 +- lib/cu_up/pdu_session_manager.h | 10 +- lib/cu_up/pdu_session_manager_impl.cpp | 28 +- lib/e1ap/common/e1ap_asn1_converters.h | 228 ++----------- lib/e1ap/cu_cp/e1ap_cu_cp_asn1_helpers.h | 2 +- lib/e1ap/cu_cp/e1ap_cu_cp_impl.cpp | 4 +- lib/e1ap/cu_up/e1ap_cu_up_asn1_helpers.h | 6 +- lib/e1ap/cu_up/e1ap_cu_up_impl.cpp | 4 +- lib/f1ap/cu_cp/f1ap_asn1_converters.h | 199 ++---------- .../cu_cp/procedures/f1_setup_procedure.cpp | 4 +- .../ue_context_modification_procedure.cpp | 2 +- .../ue_context_release_procedure.cpp | 2 +- lib/ngap/ngap_asn1_converters.h | 171 ++-------- lib/ngap/ngap_asn1_helpers.h | 6 +- lib/ngap/ngap_error_indication_helper.h | 4 +- lib/ngap/ngap_impl.cpp | 48 +-- lib/ngap/ngap_impl.h | 2 +- lib/ngap/ngap_validators/ngap_validators.cpp | 6 +- .../ngap_initial_context_setup_procedure.cpp | 4 +- ..._pdu_session_resource_modify_procedure.cpp | 3 +- ...p_pdu_session_resource_setup_procedure.cpp | 3 +- lib/ran/CMakeLists.txt | 3 + lib/ran/cause/e1ap_cause_converters.cpp | 89 ++++++ lib/ran/cause/f1ap_cause_converters.cpp | 94 ++++++ lib/ran/cause/ngap_cause_converters.cpp | 238 ++++++++++++++ .../rrc_reconfiguration_procedure.cpp | 8 +- .../rrc_reestablishment_procedure.cpp | 4 +- lib/rrc/ue/rrc_ue_impl.cpp | 2 +- lib/rrc/ue/rrc_ue_impl.h | 2 +- lib/rrc/ue/rrc_ue_message_handlers.cpp | 10 +- tests/unittests/asn1/CMakeLists.txt | 2 +- .../asn1/asn1_cause_conversion_test.cpp | 299 +++++++++--------- .../cu_cp/du_processor_test_messages.cpp | 9 +- .../cu_up/pdu_session_manager_test.cpp | 13 +- .../e1ap/common/e1ap_cu_cp_test_messages.cpp | 2 +- .../cu_cp/e1ap_cu_cp_setup_procedure_test.cpp | 2 +- ...p_cu_ue_context_release_procedure_test.cpp | 2 +- .../unittests/ngap/ngap_nas_message_test.cpp | 4 +- tests/unittests/ngap/test_helpers.h | 2 +- 73 files changed, 1281 insertions(+), 1045 deletions(-) delete mode 100644 include/srsran/ran/cause.h create mode 100644 include/srsran/ran/cause/common.h create mode 100644 include/srsran/ran/cause/e1ap_cause.h create mode 100644 include/srsran/ran/cause/e1ap_cause_converters.h create mode 100644 include/srsran/ran/cause/f1ap_cause.h create mode 100644 include/srsran/ran/cause/f1ap_cause_converters.h create mode 100644 include/srsran/ran/cause/ngap_cause.h create mode 100644 include/srsran/ran/cause/ngap_cause_converters.h create mode 100644 lib/ran/cause/e1ap_cause_converters.cpp create mode 100644 lib/ran/cause/f1ap_cause_converters.cpp create mode 100644 lib/ran/cause/ngap_cause_converters.cpp diff --git a/include/srsran/cu_cp/cu_cp_types.h b/include/srsran/cu_cp/cu_cp_types.h index f53ee4a923..93f5038e4c 100644 --- a/include/srsran/cu_cp/cu_cp_types.h +++ b/include/srsran/cu_cp/cu_cp_types.h @@ -14,7 +14,7 @@ #include "srsran/adt/optional.h" #include "srsran/adt/slotted_array.h" #include "srsran/pdcp/pdcp_config.h" -#include "srsran/ran/cause.h" +#include "srsran/ran/cause/ngap_cause.h" #include "srsran/ran/crit_diagnostics.h" #include "srsran/ran/cu_types.h" #include "srsran/ran/lcid.h" @@ -315,7 +315,7 @@ struct cu_cp_associated_qos_flow { }; struct cu_cp_qos_flow_with_cause_item { qos_flow_id_t qos_flow_id = qos_flow_id_t::invalid; - cause_t cause; + ngap_cause_t cause; }; using cu_cp_qos_flow_failed_to_setup_item = cu_cp_qos_flow_with_cause_item; @@ -339,7 +339,7 @@ struct cu_cp_pdu_session_res_setup_response_item { }; struct cu_cp_pdu_session_resource_setup_unsuccessful_transfer { - cause_t cause; + ngap_cause_t cause; optional crit_diagnostics; }; @@ -355,7 +355,7 @@ struct cu_cp_pdu_session_resource_setup_response { }; struct cu_cp_pdu_session_res_release_cmd_transfer { - cause_t cause; + ngap_cause_t cause; }; struct cu_cp_pdu_session_res_to_release_item_rel_cmd { @@ -466,14 +466,14 @@ struct cu_cp_pdu_session_resource_modify_response { }; struct cu_cp_ue_context_release_command { - ue_index_t ue_index = ue_index_t::invalid; - cause_t cause; + ue_index_t ue_index = ue_index_t::invalid; + ngap_cause_t cause; }; struct cu_cp_ue_context_release_request { ue_index_t ue_index = ue_index_t::invalid; std::vector pdu_session_res_list_cxt_rel_req; - cause_t cause; + ngap_cause_t cause; }; struct cu_cp_recommended_cell_item { diff --git a/include/srsran/e1ap/common/e1_setup_messages.h b/include/srsran/e1ap/common/e1_setup_messages.h index a4c8edc283..fa6d4b0e04 100644 --- a/include/srsran/e1ap/common/e1_setup_messages.h +++ b/include/srsran/e1ap/common/e1_setup_messages.h @@ -10,7 +10,7 @@ #pragma once -#include "srsran/ran/cause.h" +#include "srsran/ran/cause/e1ap_cause.h" #include "srsran/ran/crit_diagnostics.h" #include "srsran/ran/cu_types.h" @@ -37,7 +37,7 @@ struct cu_up_e1_setup_response { optional gnb_cu_cp_name; // e1 setup failure - optional cause; + optional cause; optional crit_diagnostics; }; diff --git a/include/srsran/e1ap/common/e1ap_types.h b/include/srsran/e1ap/common/e1ap_types.h index 6a3943a685..0d0f4b1f52 100644 --- a/include/srsran/e1ap/common/e1ap_types.h +++ b/include/srsran/e1ap/common/e1ap_types.h @@ -14,7 +14,7 @@ #include "srsran/adt/optional.h" #include "srsran/adt/slotted_array.h" #include "srsran/pdcp/pdcp_config.h" -#include "srsran/ran/cause.h" +#include "srsran/ran/cause/e1ap_cause.h" #include "srsran/ran/cu_types.h" #include "srsran/ran/lcid.h" #include "srsran/ran/up_transport_layer_info.h" @@ -204,7 +204,7 @@ struct e1ap_qos_flow_item { struct e1ap_qos_flow_failed_item { qos_flow_id_t qos_flow_id = qos_flow_id_t::invalid; - cause_t cause; + e1ap_cause_t cause; }; struct e1ap_data_forwarding_info { @@ -221,8 +221,8 @@ struct e1ap_drb_setup_item_ng_ran { }; struct e1ap_drb_failed_item_ng_ran { - drb_id_t drb_id = drb_id_t::invalid; - cause_t cause; + drb_id_t drb_id = drb_id_t::invalid; + e1ap_cause_t cause; }; struct e1ap_pdu_session_resource_setup_modification_item { @@ -237,7 +237,7 @@ struct e1ap_pdu_session_resource_setup_modification_item { struct e1ap_pdu_session_resource_failed_item { pdu_session_id_t pdu_session_id = pdu_session_id_t::invalid; - cause_t cause; + e1ap_cause_t cause; }; struct e1ap_crit_diagnostics_item { diff --git a/include/srsran/e1ap/cu_cp/e1ap_cu_cp_bearer_context_update.h b/include/srsran/e1ap/cu_cp/e1ap_cu_cp_bearer_context_update.h index a6c7ba52bf..d3a4678f9b 100644 --- a/include/srsran/e1ap/cu_cp/e1ap_cu_cp_bearer_context_update.h +++ b/include/srsran/e1ap/cu_cp/e1ap_cu_cp_bearer_context_update.h @@ -38,7 +38,7 @@ struct e1ap_bearer_context_setup_response { slotted_id_vector pdu_session_resource_failed_list; // Bearer Context Setup Failure - optional cause; + optional cause; // Common optional crit_diagnostics; @@ -69,15 +69,15 @@ struct e1ap_bearer_context_modification_response { slotted_id_vector pdu_session_resource_failed_to_modify_list; // Bearer Context Modification Failure - optional cause; + optional cause; // Common optional crit_diagnostics; }; struct e1ap_bearer_context_release_command { - ue_index_t ue_index = ue_index_t::invalid; - cause_t cause; + ue_index_t ue_index = ue_index_t::invalid; + e1ap_cause_t cause; }; } // namespace srs_cu_cp diff --git a/include/srsran/e1ap/cu_up/e1ap_cu_up_bearer_context_update.h b/include/srsran/e1ap/cu_up/e1ap_cu_up_bearer_context_update.h index 3a9e98f9dd..ff8200e4b2 100644 --- a/include/srsran/e1ap/cu_up/e1ap_cu_up_bearer_context_update.h +++ b/include/srsran/e1ap/cu_up/e1ap_cu_up_bearer_context_update.h @@ -40,7 +40,7 @@ struct e1ap_bearer_context_setup_response { slotted_id_vector pdu_session_resource_failed_list; // Bearer Context Setup Failure - optional cause; + optional cause; // Common optional crit_diagnostics; @@ -75,7 +75,7 @@ struct e1ap_bearer_context_modification_response { slotted_id_vector pdu_session_resource_failed_to_modify_list; // Bearer Context Modification Failure - optional cause; + optional cause; // Common optional crit_diagnostics; @@ -83,8 +83,8 @@ struct e1ap_bearer_context_modification_response { /// \brief Request to release a bearer context. struct e1ap_bearer_context_release_command { - ue_index_t ue_index = INVALID_UE_INDEX; - cause_t cause; // Cause of the release. + ue_index_t ue_index = INVALID_UE_INDEX; + e1ap_cause_t cause; // Cause of the release. }; } // namespace srs_cu_up diff --git a/include/srsran/f1ap/cu_cp/du_setup_notifier.h b/include/srsran/f1ap/cu_cp/du_setup_notifier.h index 90947d905a..638a0020d1 100644 --- a/include/srsran/f1ap/cu_cp/du_setup_notifier.h +++ b/include/srsran/f1ap/cu_cp/du_setup_notifier.h @@ -12,7 +12,7 @@ #include "srsran/adt/optional.h" #include "srsran/cu_cp/cu_cp_types.h" -#include "srsran/ran/cause.h" +#include "srsran/ran/cause/f1ap_cause.h" #include "srsran/ran/crit_diagnostics.h" #include "srsran/ran/gnb_du_id.h" #include "srsran/ran/nr_cgi.h" @@ -45,8 +45,8 @@ struct du_setup_result { uint8_t gnb_cu_rrc_version; }; struct rejected { - cause_t cause; - std::string cause_str; + f1ap_cause_t cause; + std::string cause_str; }; variant result; diff --git a/include/srsran/f1ap/cu_cp/f1ap_cu.h b/include/srsran/f1ap/cu_cp/f1ap_cu.h index 99e5b28504..8314b942bb 100644 --- a/include/srsran/f1ap/cu_cp/f1ap_cu.h +++ b/include/srsran/f1ap/cu_cp/f1ap_cu.h @@ -42,7 +42,7 @@ class f1ap_rrc_message_handler struct f1ap_ue_context_release_command { ue_index_t ue_index = ue_index_t::invalid; - cause_t cause; + f1ap_cause_t cause; byte_buffer rrc_release_pdu; optional srb_id; }; diff --git a/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h b/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h index d964522c79..5009ac8626 100644 --- a/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h +++ b/include/srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h @@ -12,7 +12,7 @@ #include "srsran/cu_cp/cu_cp_types.h" #include "srsran/f1ap/common/f1ap_ue_id.h" -#include "srsran/ran/cause.h" +#include "srsran/ran/cause/f1ap_cause.h" #include "srsran/ran/cu_types.h" #include "srsran/ran/lcid.h" #include "srsran/ran/nr_cgi.h" @@ -163,18 +163,18 @@ struct f1ap_drbs_setup_mod_item { }; struct f1ap_srbs_failed_to_be_setup_mod_item { - srb_id_t srb_id = srb_id_t::nulltype; - optional cause; + srb_id_t srb_id = srb_id_t::nulltype; + optional cause; }; struct f1ap_drbs_failed_to_be_setup_mod_item { - drb_id_t drb_id = drb_id_t::invalid; - optional cause; + drb_id_t drb_id = drb_id_t::invalid; + optional cause; }; struct f1ap_scell_failed_to_setup_mod_item { - nr_cell_global_id_t scell_id; - optional cause; + nr_cell_global_id_t scell_id; + optional cause; }; struct f1ap_srbs_setup_mod_item { @@ -204,7 +204,7 @@ struct f1ap_ue_context_setup_response { slotted_id_vector srbs_setup_list; // max size = 8 // UE Context Setup Failure - optional cause; + optional cause; std::vector potential_sp_cell_list; // max size = 64 // Common @@ -288,7 +288,7 @@ struct f1ap_ue_context_modification_response { optional full_cfg; // UE Context Modification Failure - optional cause; + optional cause; // Common optional crit_diagnostics; @@ -296,8 +296,8 @@ struct f1ap_ue_context_modification_response { /// \brief Request Command for F1AP UE CONTEXT Release Request. struct f1ap_ue_context_release_request { - ue_index_t ue_index; - cause_t cause; + ue_index_t ue_index; + f1ap_cause_t cause; }; } // namespace srs_cu_cp diff --git a/include/srsran/ngap/ngap_handover.h b/include/srsran/ngap/ngap_handover.h index a12ce9ddbd..0ad29ff9e2 100644 --- a/include/srsran/ngap/ngap_handover.h +++ b/include/srsran/ngap/ngap_handover.h @@ -64,11 +64,11 @@ struct ngap_cell_type { }; struct ngap_last_visited_ngran_cell_info { - nr_cell_global_id_t global_cell_id; - ngap_cell_type cell_type; - uint16_t time_ue_stayed_in_cell; - optional time_ue_stayed_in_cell_enhanced_granularity; - optional ho_cause_value; + nr_cell_global_id_t global_cell_id; + ngap_cell_type cell_type; + uint16_t time_ue_stayed_in_cell; + optional time_ue_stayed_in_cell_enhanced_granularity; + optional ho_cause_value; }; struct ngap_last_visited_cell_item { @@ -87,7 +87,7 @@ struct ngap_source_ngran_node_to_target_ngran_node_transparent_container { struct ngap_handover_request { ue_index_t ue_index = ue_index_t::invalid; ngap_handov_type handov_type; - cause_t cause; + ngap_cause_t cause; ngap_ue_aggr_max_bit_rate ue_aggr_max_bit_rate; // TODO: Add optional core_network_assist_info_for_inactive security::security_context security_context; @@ -146,7 +146,7 @@ struct ngap_handover_resource_allocation_response { ngap_target_ngran_node_to_source_ngran_node_transparent_container target_to_source_transparent_container; // handover request failure - cause_t cause; + ngap_cause_t cause; // common optional crit_diagnostics; diff --git a/include/srsran/ngap/ngap_init_context_setup.h b/include/srsran/ngap/ngap_init_context_setup.h index 19159305f2..b0c6a22d33 100644 --- a/include/srsran/ngap/ngap_init_context_setup.h +++ b/include/srsran/ngap/ngap_init_context_setup.h @@ -42,7 +42,7 @@ struct ngap_init_context_setup_request { }; struct ngap_init_context_setup_failure { - cause_t cause; + ngap_cause_t cause; slotted_id_vector pdu_session_res_failed_to_setup_items; optional crit_diagnostics; }; diff --git a/include/srsran/ngap/ngap_setup.h b/include/srsran/ngap/ngap_setup.h index 19cc0440df..d3832c527f 100644 --- a/include/srsran/ngap/ngap_setup.h +++ b/include/srsran/ngap/ngap_setup.h @@ -62,7 +62,7 @@ struct ngap_ng_setup_response { }; struct ngap_ng_setup_failure { - cause_t cause; + ngap_cause_t cause; optional crit_diagnostics; }; diff --git a/include/srsran/ran/cause.h b/include/srsran/ran/cause.h deleted file mode 100644 index 4e8872d963..0000000000 --- a/include/srsran/ran/cause.h +++ /dev/null @@ -1,206 +0,0 @@ -/* - * - * Copyright 2021-2024 Software Radio Systems Limited - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the distribution. - * - */ - -#pragma once - -#include "srsran/adt/variant.h" - -namespace srsran { - -constexpr uint16_t NGAP_RADIO_NETWORK_CAUSE_OFFSET = 100; -constexpr uint16_t F1AP_RADIO_NETWORK_CAUSE_OFFSET = 200; -constexpr uint16_t E1AP_RADIO_NETWORK_CAUSE_OFFSET = 300; - -enum class cause_radio_network_t : uint16_t { - // Common - unspecified = 0, - interaction_with_other_proc, - res_not_available_for_the_slice, - - // NGAP and F1AP - cell_not_available, - - // NGAP and E1AP - not_supported_5qi_value, - up_integrity_protection_not_possible, - up_confidentiality_protection_not_possible, - multiple_pdu_session_id_instances, - unknown_pdu_session_id, - multiple_qos_flow_id_instances, - invalid_qos_combination, - - // F1AP and E1AP - not_supported_qci_value, - multiple_drb_id_instances, - unknown_drb_id, - proc_cancelled, - normal_release, - no_radio_res_available, - action_desirable_for_radio_reasons, - release_due_to_pre_emption, - npn_not_supported, - existing_meas_id, - meas_temporarily_not_available, - meas_not_supported_for_the_obj, - - // NGAP - txnrelocoverall_expiry = NGAP_RADIO_NETWORK_CAUSE_OFFSET + 1, - successful_ho, - release_due_to_ngran_generated_reason, - release_due_to_5gc_generated_reason, - ho_cancelled, - partial_ho, - ho_fail_in_target_5_gc_ngran_node_or_target_sys, - ho_target_not_allowed, - tngrelocoverall_expiry, - tngrelocprep_expiry, - unknown_target_id = NGAP_RADIO_NETWORK_CAUSE_OFFSET + 12, - no_radio_res_available_in_target_cell, - unknown_local_ue_ngap_id, - inconsistent_remote_ue_ngap_id, - ho_desirable_for_radio_reason, - time_crit_ho, - res_optim_ho, - reduce_load_in_serving_cell, - user_inactivity, - radio_conn_with_ue_lost, - radio_res_not_available, - fail_in_radio_interface_proc = NGAP_RADIO_NETWORK_CAUSE_OFFSET + 24, - unkown_qos_flow_id = NGAP_RADIO_NETWORK_CAUSE_OFFSET + 27, - encryption_and_or_integrity_protection_algorithms_not_supported = NGAP_RADIO_NETWORK_CAUSE_OFFSET + 30, - ng_intra_sys_ho_triggered, - ng_inter_sys_ho_triggered, - xn_ho_triggered, - ue_context_transfer = NGAP_RADIO_NETWORK_CAUSE_OFFSET + 35, - ims_voice_eps_fallback_or_rat_fallback_triggered, - slice_not_supported = NGAP_RADIO_NETWORK_CAUSE_OFFSET + 39, - ue_in_rrc_inactive_state_not_reachable, - redirection, - ue_max_integrity_protected_data_rate_reason = NGAP_RADIO_NETWORK_CAUSE_OFFSET + 43, - release_due_to_cn_detected_mob, - - // F1AP - rl_fail_rlc = F1AP_RADIO_NETWORK_CAUSE_OFFSET + 1, - unknown_or_already_allocated_gnb_cu_ue_f1ap_id, - unknown_or_already_allocated_gnb_du_ue_f1ap_id, - unknown_or_inconsistent_pair_of_ue_f1ap_id, - rl_fail_others = F1AP_RADIO_NETWORK_CAUSE_OFFSET + 12, - ue_rejection, - amf_initiated_abnormal_release = F1AP_RADIO_NETWORK_CAUSE_OFFSET + 15, - plmn_not_served_by_the_gnb_cu = F1AP_RADIO_NETWORK_CAUSE_OFFSET + 17, - multiple_bh_rlc_ch_id_instances = F1AP_RADIO_NETWORK_CAUSE_OFFSET + 20, - unknown_bh_rlc_ch_id, - cho_cpc_res_tobechanged, - npn_access_denied = F1AP_RADIO_NETWORK_CAUSE_OFFSET + 24, - gnb_cu_cell_capacity_exceeded, - report_characteristics_empty, - unknown_bh_address = F1AP_RADIO_NETWORK_CAUSE_OFFSET + 30, - unknown_bap_routing_id, - insufficient_ue_cap, - scg_activation_deactivation_fail, - scg_deactivation_fail_due_to_data_tx, - requested_item_not_supported_on_time, - unknown_or_already_allocated_gnb_cu_mbs_f1ap_id, - unknown_or_already_allocated_gnb_du_mbs_f1ap_id, - unknown_or_inconsistent_pair_of_mbs_f1ap_id, - unknown_or_inconsistent_mrb_id, - tat_sdt_expiry, - - // E1AP - unknown_or_already_allocated_gnb_cu_cp_ue_e1ap_id = E1AP_RADIO_NETWORK_CAUSE_OFFSET + 1, - unknown_or_already_allocated_gnb_cu_up_ue_e1ap_id, - unknown_or_inconsistent_pair_of_ue_e1ap_id, - ppdcp_count_wrap_around = E1AP_RADIO_NETWORK_CAUSE_OFFSET + 5, - encryption_algorithms_not_supported = E1AP_RADIO_NETWORK_CAUSE_OFFSET + 8, - integrity_protection_algorithms_not_supported, - unknown_qos_flow_id = E1AP_RADIO_NETWORK_CAUSE_OFFSET + 15, - pdcp_cfg_not_supported = E1AP_RADIO_NETWORK_CAUSE_OFFSET + 24, - ue_dl_max_ip_data_rate_reason, - up_integrity_protection_fail, - rsn_not_available_for_the_up = E1AP_RADIO_NETWORK_CAUSE_OFFSET + 28, - report_characteristic_empty = E1AP_RADIO_NETWORK_CAUSE_OFFSET + 30 -}; - -enum class cause_transport_t : uint8_t { - transport_res_unavailable = 0, - unspecified, - unknown_tnl_address_for_iab, // only F1AP and E1AP - unknown_up_tnl_info_for_iab // only F1AP -}; - -enum class cause_nas_t : uint8_t { normal_release = 0, authentication_fail, deregister, unspecified }; // only NGAP - -enum class cause_protocol_t : uint8_t { - transfer_syntax_error = 0, - abstract_syntax_error_reject, - abstract_syntax_error_ignore_and_notify, - msg_not_compatible_with_receiver_state, - semantic_error, - abstract_syntax_error_falsely_constructed_msg, - unspecified -}; - -enum class cause_misc_t : uint8_t { - ctrl_processing_overload = 0, - not_enough_user_plane_processing_res, - hardware_fail, - om_intervention, - unknown_plmn_or_sn_pn, // only NGAP - unspecified -}; - -using cause_t = variant; - -// Establishment cause - -enum class establishment_cause_t : uint8_t { - emergency = 0, - high_prio_access, - mt_access, - mo_sig, - mo_data, - mo_voice_call, - mo_video_call, - mo_sms, - mps_prio_access, - mcs_prio_access -}; - -} // namespace srsran - -namespace fmt { - -// cause_t formatter -template <> -struct formatter { - template - auto parse(ParseContext& ctx) -> decltype(ctx.begin()) - { - return ctx.begin(); - } - - template - auto format(srsran::cause_t o, FormatContext& ctx) -> decltype(std::declval().out()) - { - if (srsran::variant_holds_alternative(o)) { - return format_to(ctx.out(), "radio_network-id{}", srsran::variant_get(o)); - } else if (srsran::variant_holds_alternative(o)) { - return format_to(ctx.out(), "transport-id{}", srsran::variant_get(o)); - } else if (srsran::variant_holds_alternative(o)) { - return format_to(ctx.out(), "nas-id{}", srsran::variant_get(o)); - } else if (srsran::variant_holds_alternative(o)) { - return format_to(ctx.out(), "protocol-id{}", srsran::variant_get(o)); - } else { - return format_to(ctx.out(), "misc-id{}", srsran::variant_get(o)); - } - } -}; - -} // namespace fmt diff --git a/include/srsran/ran/cause/common.h b/include/srsran/ran/cause/common.h new file mode 100644 index 0000000000..9fc14e2c10 --- /dev/null +++ b/include/srsran/ran/cause/common.h @@ -0,0 +1,50 @@ +/* + * + * 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 { + +enum class cause_protocol_t : uint8_t { + transfer_syntax_error = 0, + abstract_syntax_error_reject, + abstract_syntax_error_ignore_and_notify, + msg_not_compatible_with_receiver_state, + semantic_error, + abstract_syntax_error_falsely_constructed_msg, + unspecified +}; + +enum class cause_misc_t : uint8_t { + ctrl_processing_overload = 0, + not_enough_user_plane_processing_res, + hardware_fail, + om_intervention, + unspecified +}; + +// Establishment cause + +enum class establishment_cause_t : uint8_t { + emergency = 0, + high_prio_access, + mt_access, + mo_sig, + mo_data, + mo_voice_call, + mo_video_call, + mo_sms, + mps_prio_access, + mcs_prio_access +}; + +} // namespace srsran diff --git a/include/srsran/ran/cause/e1ap_cause.h b/include/srsran/ran/cause/e1ap_cause.h new file mode 100644 index 0000000000..47daf79446 --- /dev/null +++ b/include/srsran/ran/cause/e1ap_cause.h @@ -0,0 +1,88 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +#include "common.h" +#include "srsran/adt/variant.h" +#include "fmt/format.h" + +namespace srsran { + +enum class e1ap_cause_radio_network_t : uint8_t { + unspecified = 0, + unknown_or_already_allocated_gnb_cu_cp_ue_e1ap_id, + unknown_or_already_allocated_gnb_cu_up_ue_e1ap_id, + unknown_or_inconsistent_pair_of_ue_e1ap_id, + interaction_with_other_proc, + ppdcp_count_wrap_around, + not_supported_qci_value, + not_supported_5qi_value, + encryption_algorithms_not_supported, + integrity_protection_algorithms_not_supported, + up_integrity_protection_not_possible, + up_confidentiality_protection_not_possible, + multiple_pdu_session_id_instances, + unknown_pdu_session_id, + multiple_qos_flow_id_instances, + unknown_qos_flow_id, + multiple_drb_id_instances, + unknown_drb_id, + invalid_qos_combination, + proc_cancelled, + normal_release, + no_radio_res_available, + action_desirable_for_radio_reasons, + res_not_available_for_the_slice, + pdcp_cfg_not_supported, + ue_dl_max_ip_data_rate_reason, + up_integrity_protection_fail, + release_due_to_pre_emption, + rsn_not_available_for_the_up, + npn_not_supported, + report_characteristic_empty, + existing_meas_id, + meas_temporarily_not_available, + meas_not_supported_for_the_obj +}; + +enum class e1ap_cause_transport_t : uint8_t { unspecified = 0, transport_res_unavailable, unknown_tnl_address_for_iab }; + +using e1ap_cause_t = variant; + +} // namespace srsran + +namespace fmt { + +// e1ap_cause_t formatter +template <> +struct formatter { + template + auto parse(ParseContext& ctx) -> decltype(ctx.begin()) + { + return ctx.begin(); + } + + template + auto format(srsran::e1ap_cause_t o, FormatContext& ctx) -> decltype(std::declval().out()) + { + if (srsran::variant_holds_alternative(o)) { + return format_to(ctx.out(), "radio_network-id{}", srsran::variant_get(o)); + } else if (srsran::variant_holds_alternative(o)) { + return format_to(ctx.out(), "transport-id{}", srsran::variant_get(o)); + } else if (srsran::variant_holds_alternative(o)) { + return format_to(ctx.out(), "protocol-id{}", srsran::variant_get(o)); + } else { + return format_to(ctx.out(), "misc-id{}", srsran::variant_get(o)); + } + } +}; + +} // namespace fmt diff --git a/include/srsran/ran/cause/e1ap_cause_converters.h b/include/srsran/ran/cause/e1ap_cause_converters.h new file mode 100644 index 0000000000..e4caeab49e --- /dev/null +++ b/include/srsran/ran/cause/e1ap_cause_converters.h @@ -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. + * + */ + +#pragma once + +#include "e1ap_cause.h" +#include "ngap_cause.h" + +namespace srsran { + +/// \brief Converts an E1AP cause to an NGAP cause. +ngap_cause_t e1ap_to_ngap_cause(e1ap_cause_t e1ap_cause); + +} // namespace srsran diff --git a/include/srsran/ran/cause/f1ap_cause.h b/include/srsran/ran/cause/f1ap_cause.h new file mode 100644 index 0000000000..813133e797 --- /dev/null +++ b/include/srsran/ran/cause/f1ap_cause.h @@ -0,0 +1,100 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +#include "common.h" +#include "srsran/adt/variant.h" +#include "fmt/format.h" + +namespace srsran { + +enum class f1ap_cause_radio_network_t : uint8_t { + unspecified = 0, + rl_fail_rlc, + unknown_or_already_allocated_gnb_cu_ue_f1ap_id, + unknown_or_already_allocated_gnb_du_ue_f1ap_id, + unknown_or_inconsistent_pair_of_ue_f1ap_id, + interaction_with_other_proc, + not_supported_qci_value, + action_desirable_for_radio_reasons, + no_radio_res_available, + proc_cancelled, + normal_release, + cell_not_available, + rl_fail_others, + ue_rejection, + res_not_available_for_the_slice, + amf_initiated_abnormal_release, + release_due_to_pre_emption, + plmn_not_served_by_the_gnb_cu, + multiple_drb_id_instances, + unknown_drb_id, + multiple_bh_rlc_ch_id_instances, + unknown_bh_rlc_ch_id, + cho_cpc_res_tobechanged, + npn_not_supported, + npn_access_denied, + gnb_cu_cell_capacity_exceeded, + report_characteristics_empty, + existing_meas_id, + meas_temporarily_not_available, + meas_not_supported_for_the_obj, + unknown_bh_address, + unknown_bap_routing_id, + insufficient_ue_cap, + scg_activation_deactivation_fail, + scg_deactivation_fail_due_to_data_tx, + requested_item_not_supported_on_time, + unknown_or_already_allocated_gnb_cu_mbs_f1ap_id, + unknown_or_already_allocated_gnb_du_mbs_f1ap_id, + unknown_or_inconsistent_pair_of_mbs_f1ap_id, + unknown_or_inconsistent_mrb_id, + tat_sdt_expiry +}; + +enum class f1ap_cause_transport_t : uint8_t { + unspecified = 0, + transport_res_unavailable, + unknown_tnl_address_for_iab, + unknown_up_tnl_info_for_iab +}; + +using f1ap_cause_t = variant; + +} // namespace srsran + +namespace fmt { + +// f1ap_cause_t formatter +template <> +struct formatter { + template + auto parse(ParseContext& ctx) -> decltype(ctx.begin()) + { + return ctx.begin(); + } + + template + auto format(srsran::f1ap_cause_t o, FormatContext& ctx) -> decltype(std::declval().out()) + { + if (srsran::variant_holds_alternative(o)) { + return format_to(ctx.out(), "radio_network-id{}", srsran::variant_get(o)); + } else if (srsran::variant_holds_alternative(o)) { + return format_to(ctx.out(), "transport-id{}", srsran::variant_get(o)); + } else if (srsran::variant_holds_alternative(o)) { + return format_to(ctx.out(), "protocol-id{}", srsran::variant_get(o)); + } else { + return format_to(ctx.out(), "misc-id{}", srsran::variant_get(o)); + } + } +}; + +} // namespace fmt diff --git a/include/srsran/ran/cause/f1ap_cause_converters.h b/include/srsran/ran/cause/f1ap_cause_converters.h new file mode 100644 index 0000000000..b8224bdd39 --- /dev/null +++ b/include/srsran/ran/cause/f1ap_cause_converters.h @@ -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. + * + */ + +#pragma once + +#include "f1ap_cause.h" +#include "ngap_cause.h" + +namespace srsran { + +/// \brief Converts an F1AP cause to an NGAP cause. +ngap_cause_t f1ap_to_ngap_cause(f1ap_cause_t f1ap_cause); + +} // namespace srsran diff --git a/include/srsran/ran/cause/ngap_cause.h b/include/srsran/ran/cause/ngap_cause.h new file mode 100644 index 0000000000..d0cff22c81 --- /dev/null +++ b/include/srsran/ran/cause/ngap_cause.h @@ -0,0 +1,128 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +#include "common.h" +#include "srsran/adt/variant.h" +#include "fmt/format.h" + +namespace srsran { + +enum class ngap_cause_radio_network_t : uint8_t { + unspecified = 0, + txnrelocoverall_expiry, + successful_ho, + release_due_to_ngran_generated_reason, + release_due_to_5gc_generated_reason, + ho_cancelled, + partial_ho, + ho_fail_in_target_5_gc_ngran_node_or_target_sys, + ho_target_not_allowed, + tngrelocoverall_expiry, + tngrelocprep_expiry, + cell_not_available, + unknown_target_id, + no_radio_res_available_in_target_cell, + unknown_local_ue_ngap_id, + inconsistent_remote_ue_ngap_id, + ho_desirable_for_radio_reason, + time_crit_ho, + res_optim_ho, + reduce_load_in_serving_cell, + user_inactivity, + radio_conn_with_ue_lost, + radio_res_not_available, + invalid_qos_combination, + fail_in_radio_interface_proc, + interaction_with_other_proc, + unknown_pdu_session_id, + unkown_qos_flow_id, + multiple_pdu_session_id_instances, + multiple_qos_flow_id_instances, + encryption_and_or_integrity_protection_algorithms_not_supported, + ng_intra_sys_ho_triggered, + ng_inter_sys_ho_triggered, + xn_ho_triggered, + not_supported_5qi_value, + ue_context_transfer, + ims_voice_eps_fallback_or_rat_fallback_triggered, + up_integrity_protection_not_possible, + up_confidentiality_protection_not_possible, + slice_not_supported, + ue_in_rrc_inactive_state_not_reachable, + redirection, + res_not_available_for_the_slice, + ue_max_integrity_protected_data_rate_reason, + release_due_to_cn_detected_mob, + n26_interface_not_available, + release_due_to_pre_emption, + multiple_location_report_ref_id_instances, + rsn_not_available_for_the_up, + npn_access_denied, + cag_only_access_denied, + insufficient_ue_cap, + redcap_ue_not_supported, + unknown_mbs_session_id, + indicated_mbs_session_area_info_not_served_by_the_gnb, + inconsistent_slice_info_for_the_session, + misaligned_assoc_for_multicast_unicast +}; + +enum class ngap_cause_transport_t : uint8_t { + transport_res_unavailable = 0, + unspecified, +}; + +enum class cause_nas_t : uint8_t { normal_release = 0, authentication_fail, deregister, unspecified }; // only NGAP + +enum class ngap_cause_misc_t : uint8_t { + ctrl_processing_overload = 0, + not_enough_user_plane_processing_res, + hardware_fail, + om_intervention, + unknown_plmn_or_sn_pn, + unspecified +}; + +using ngap_cause_t = + variant; + +} // namespace srsran + +namespace fmt { + +// ngap_cause_t formatter +template <> +struct formatter { + template + auto parse(ParseContext& ctx) -> decltype(ctx.begin()) + { + return ctx.begin(); + } + + template + auto format(srsran::ngap_cause_t o, FormatContext& ctx) -> decltype(std::declval().out()) + { + if (srsran::variant_holds_alternative(o)) { + return format_to(ctx.out(), "radio_network-id{}", srsran::variant_get(o)); + } else if (srsran::variant_holds_alternative(o)) { + return format_to(ctx.out(), "transport-id{}", srsran::variant_get(o)); + } else if (srsran::variant_holds_alternative(o)) { + return format_to(ctx.out(), "nas-id{}", srsran::variant_get(o)); + } else if (srsran::variant_holds_alternative(o)) { + return format_to(ctx.out(), "protocol-id{}", srsran::variant_get(o)); + } else { + return format_to(ctx.out(), "misc-id{}", srsran::variant_get(o)); + } + } +}; + +} // namespace fmt diff --git a/include/srsran/ran/cause/ngap_cause_converters.h b/include/srsran/ran/cause/ngap_cause_converters.h new file mode 100644 index 0000000000..f84ddc4986 --- /dev/null +++ b/include/srsran/ran/cause/ngap_cause_converters.h @@ -0,0 +1,25 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +#include "e1ap_cause.h" +#include "f1ap_cause.h" +#include "ngap_cause.h" + +namespace srsran { + +/// \brief Converts an NGAP cause to an F1AP cause. +f1ap_cause_t ngap_to_f1ap_cause(ngap_cause_t ngap_cause); + +/// \brief Converts an NGAP cause to an E1AP cause. +e1ap_cause_t ngap_to_e1ap_cause(ngap_cause_t ngap_cause); + +} // namespace srsran diff --git a/include/srsran/rrc/rrc_ue.h b/include/srsran/rrc/rrc_ue.h index 9dca9d8e62..04fb6b2870 100644 --- a/include/srsran/rrc/rrc_ue.h +++ b/include/srsran/rrc/rrc_ue.h @@ -60,7 +60,7 @@ class rrc_ue_setup_proc_notifier virtual void on_new_dl_ccch(const asn1::rrc_nr::dl_ccch_msg_s& dl_ccch_msg) = 0; /// \brief Notify about the need to release a UE. - virtual void on_ue_release_required(const cause_t& cause) = 0; + virtual void on_ue_release_required(const ngap_cause_t& cause) = 0; }; struct srb_creation_message { @@ -99,7 +99,7 @@ class rrc_ue_reconfiguration_proc_notifier virtual void on_new_dl_dcch(srb_id_t srb_id, const asn1::rrc_nr::dl_dcch_msg_s& dl_dcch_msg) = 0; /// \brief Notify about the need to release a UE. - virtual void on_ue_release_required(const cause_t& cause) = 0; + virtual void on_ue_release_required(const ngap_cause_t& cause) = 0; }; /// Interface used by the RRC security mode procedure diff --git a/lib/cu_cp/CMakeLists.txt b/lib/cu_cp/CMakeLists.txt index 3af0447f83..066f68cc5e 100644 --- a/lib/cu_cp/CMakeLists.txt +++ b/lib/cu_cp/CMakeLists.txt @@ -45,4 +45,4 @@ set(SOURCES add_library(srsran_cu_cp STATIC ${SOURCES}) -target_link_libraries(srsran_cu_cp srsran_cu_cp_cell_meas_manager srsran_cu_cp_mobility_manager srslog srsran_support srsran_e1ap srsran_f1ap_cu srsran_ngap srsran_rrc srsran_security) +target_link_libraries(srsran_cu_cp srsran_cu_cp_cell_meas_manager srsran_cu_cp_mobility_manager srsran_e1ap srsran_f1ap_cu srsran_ngap srsran_rrc srsran_ran srslog srsran_support srsran_security) diff --git a/lib/cu_cp/cu_up_processor/cu_up_processor_impl.cpp b/lib/cu_cp/cu_up_processor/cu_up_processor_impl.cpp index 17e22a1c4c..ecaa324b4a 100644 --- a/lib/cu_cp/cu_up_processor/cu_up_processor_impl.cpp +++ b/lib/cu_cp/cu_up_processor/cu_up_processor_impl.cpp @@ -61,7 +61,7 @@ void cu_up_processor_impl::send_cu_up_e1_setup_response() e1ap->handle_cu_up_e1_setup_response(response); } -void cu_up_processor_impl::send_cu_up_e1_setup_failure(cause_t cause) +void cu_up_processor_impl::send_cu_up_e1_setup_failure(e1ap_cause_t cause) { cu_up_e1_setup_response response; response.success = false; diff --git a/lib/cu_cp/cu_up_processor/cu_up_processor_impl.h b/lib/cu_cp/cu_up_processor/cu_up_processor_impl.h index 81fd93a339..527886f21d 100644 --- a/lib/cu_cp/cu_up_processor/cu_up_processor_impl.h +++ b/lib/cu_cp/cu_up_processor/cu_up_processor_impl.h @@ -55,7 +55,7 @@ class cu_up_processor_impl : public cu_up_processor_impl_interface /// \brief Create and transmit the GNB-CU-UP E1 Setup failure message. /// \param[in] cause The cause of the failure. - void send_cu_up_e1_setup_failure(cause_t cause); + void send_cu_up_e1_setup_failure(e1ap_cause_t cause); srslog::basic_logger& logger = srslog::fetch_basic_logger("CU-CP"); cu_up_processor_config_t cfg; diff --git a/lib/cu_cp/du_processor/du_processor_impl.cpp b/lib/cu_cp/du_processor/du_processor_impl.cpp index ba3a503113..c01696d91b 100644 --- a/lib/cu_cp/du_processor/du_processor_impl.cpp +++ b/lib/cu_cp/du_processor/du_processor_impl.cpp @@ -11,6 +11,8 @@ #include "du_processor_impl.h" #include "srsran/cu_cp/cu_cp_types.h" #include "srsran/f1ap/cu_cp/f1ap_cu_factory.h" +#include "srsran/ran/cause/f1ap_cause_converters.h" +#include "srsran/ran/cause/ngap_cause.h" #include "srsran/ran/nr_cgi_helpers.h" #include "srsran/rrc/rrc_du_factory.h" @@ -93,7 +95,7 @@ du_setup_result du_processor_impl::handle_du_setup_request(const du_setup_reques // TODO: How to handle missing optional freq and timing in meas timing config? if (!rrc_du_adapter.on_new_served_cell_list(request.gnb_du_served_cells_list)) { res.result = - du_setup_result::rejected{cause_transport_t::unspecified, "Could not establish served cell list in RRC"}; + du_setup_result::rejected{f1ap_cause_transport_t::unspecified, "Could not establish served cell list in RRC"}; return res; } @@ -315,13 +317,15 @@ void du_processor_impl::handle_du_initiated_ue_context_release_request(const f1a // Notify NGAP to request a release from the AMF CORO_AWAIT_VALUE(ngap_release_successful, - ngap_ctrl_notifier.on_ue_context_release_request(cu_cp_ue_context_release_request{ - request.ue_index, ue->get_up_resource_manager().get_pdu_sessions(), request.cause})); + ngap_ctrl_notifier.on_ue_context_release_request( + cu_cp_ue_context_release_request{request.ue_index, + ue->get_up_resource_manager().get_pdu_sessions(), + f1ap_to_ngap_cause(request.cause)})); if (!ngap_release_successful) { // Release UE from DU, if it doesn't exist in the NGAP logger.debug("ue={}: Releasing UE from DU. ReleaseRequest not sent to AMF", request.ue_index); CORO_AWAIT(handle_ue_context_release_command( - cu_cp_ue_context_release_command{request.ue_index, cause_nas_t::unspecified})); + cu_cp_ue_context_release_command{request.ue_index, ngap_cause_radio_network_t::user_inactivity})); } CORO_RETURN(); })); @@ -470,14 +474,14 @@ void du_processor_impl::handle_paging_message(cu_cp_paging_message& msg) f1ap_paging_notifier.on_paging_message(msg); } -void du_processor_impl::send_ngap_ue_context_release_request(ue_index_t ue_index, cause_t cause) +void du_processor_impl::send_ngap_ue_context_release_request(ue_index_t ue_index, ngap_cause_t cause) { du_ue* ue = ue_manager.find_du_ue(ue_index); srsran_assert(ue != nullptr, "ue={}: Could not find DU UE", ue_index); cu_cp_ue_context_release_request req; req.ue_index = ue_index; - req.cause = cause_radio_network_t::user_inactivity; + req.cause = cause; // Add PDU Session IDs auto& up_resource_manager = ue->get_up_resource_manager(); @@ -497,7 +501,7 @@ void du_processor_impl::send_ngap_ue_context_release_request(ue_index_t ue_index void du_processor_impl::handle_inactivity_notification(const cu_cp_inactivity_notification& msg) { if (msg.ue_inactive) { - send_ngap_ue_context_release_request(msg.ue_index, cause_radio_network_t::user_inactivity); + send_ngap_ue_context_release_request(msg.ue_index, ngap_cause_radio_network_t::user_inactivity); } else { logger.debug("Inactivity notification level not supported"); } diff --git a/lib/cu_cp/du_processor/du_processor_impl.h b/lib/cu_cp/du_processor/du_processor_impl.h index f3a82d3991..8e175a135b 100644 --- a/lib/cu_cp/du_processor/du_processor_impl.h +++ b/lib/cu_cp/du_processor/du_processor_impl.h @@ -152,7 +152,7 @@ class du_processor_impl : public du_processor_impl_interface, public du_setup_ha /// \brief Request UE context release over NGAP. /// \param[in] ue_index The UE. /// \param[in] cause The cause of the failure. - void send_ngap_ue_context_release_request(ue_index_t ue_index, cause_t cause); + void send_ngap_ue_context_release_request(ue_index_t ue_index, ngap_cause_t cause); srslog::basic_logger& logger = srslog::fetch_basic_logger("CU-CP"); du_processor_config_t cfg; diff --git a/lib/cu_cp/routines/mobility/inter_cu_handover_target_routine.cpp b/lib/cu_cp/routines/mobility/inter_cu_handover_target_routine.cpp index 608a2bb82c..b9be08ab22 100644 --- a/lib/cu_cp/routines/mobility/inter_cu_handover_target_routine.cpp +++ b/lib/cu_cp/routines/mobility/inter_cu_handover_target_routine.cpp @@ -11,7 +11,7 @@ #include "inter_cu_handover_target_routine.h" #include "../pdu_session_routine_helpers.h" #include "srsran/ngap/ngap_handover.h" -#include "srsran/ran/cause.h" +#include "srsran/ran/cause/e1ap_cause_converters.h" using namespace srsran; using namespace srs_cu_cp; @@ -322,7 +322,7 @@ inter_cu_handover_target_routine::generate_handover_resource_allocation_response // qos flow id qos_flow_item.qos_flow_id = flow_failed_item.qos_flow_id; // cause - qos_flow_item.cause = flow_failed_item.cause; + qos_flow_item.cause = e1ap_to_ngap_cause(flow_failed_item.cause); admitted_item.ho_request_ack_transfer.qos_flow_failed_to_setup_list.push_back(qos_flow_item); } diff --git a/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp b/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp index 1c852cd0e5..cd6367fd36 100644 --- a/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp +++ b/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp @@ -145,7 +145,7 @@ void inter_du_handover_routine::operator()(coro_contextget_ue_index(); - ue_context_release_command.cause = cause_radio_network_t::unspecified; + ue_context_release_command.cause = ngap_cause_radio_network_t::unspecified; CORO_AWAIT(source_du_processor_notifier.handle_ue_context_release_command(ue_context_release_command)); logger.debug("ue={}: \"{}\" removed source UE context", ue_context_release_command.ue_index, name()); } 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 f14e90a760..5e15a80ade 100644 --- a/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp @@ -278,7 +278,7 @@ void fill_modify_failed_list(cu_cp_pdu_session_resource_modify_response& re for (const auto& item : modify_request.pdu_session_res_modify_items) { cu_cp_pdu_session_resource_failed_to_modify_item failed_item; failed_item.pdu_session_id = item.pdu_session_id; - failed_item.unsuccessful_transfer.cause = cause_misc_t::unspecified; + failed_item.unsuccessful_transfer.cause = ngap_cause_misc_t::unspecified; response_msg.pdu_session_res_failed_to_modify_list.emplace(failed_item.pdu_session_id, failed_item); } } @@ -304,7 +304,7 @@ void mark_all_sessions_as_failed(cu_cp_pdu_session_resource_modify_response& for (const auto& modify_item : modify_request.pdu_session_res_modify_items) { cu_cp_pdu_session_resource_failed_to_modify_item failed_item; failed_item.pdu_session_id = modify_item.pdu_session_id; - failed_item.unsuccessful_transfer.cause = cause_radio_network_t::unspecified; + failed_item.unsuccessful_transfer.cause = ngap_cause_radio_network_t::unspecified; response_msg.pdu_session_res_failed_to_modify_list.emplace(failed_item.pdu_session_id, failed_item); } // No PDU session modified can be successful at the same time. @@ -327,7 +327,7 @@ pdu_session_resource_modification_routine::generate_pdu_session_resource_modify_ for (const auto& psi : next_config.pdu_sessions_failed_to_modify_list) { cu_cp_pdu_session_resource_failed_to_modify_item failed_item; failed_item.pdu_session_id = psi; - failed_item.unsuccessful_transfer.cause = cause_radio_network_t::unspecified; + failed_item.unsuccessful_transfer.cause = ngap_cause_radio_network_t::unspecified; response_msg.pdu_session_res_failed_to_modify_list.emplace(failed_item.pdu_session_id, failed_item); } } else { 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 6d1f1d9667..679c8f7601 100644 --- a/lib/cu_cp/routines/pdu_session_resource_release_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_release_routine.cpp @@ -55,14 +55,14 @@ void pdu_session_resource_release_routine::operator()( if (next_config.context_removal_required) { // Remove bearer context. bearer_context_release_command.ue_index = release_cmd.ue_index; - bearer_context_release_command.cause = cause_radio_network_t::unspecified; + bearer_context_release_command.cause = e1ap_cause_radio_network_t::unspecified; CORO_AWAIT(e1ap_ctrl_notifier.on_bearer_context_release_command(bearer_context_release_command)); // Request UE context removal. logger.info("ue={}: \"{}\" Requesting UE context release", release_cmd.ue_index, name()); ue_context_release_request.ue_index = release_cmd.ue_index; - ue_context_release_request.cause = cause_radio_network_t::unknown_pdu_session_id; + ue_context_release_request.cause = ngap_cause_radio_network_t::unknown_pdu_session_id; CORO_AWAIT(ngap_ctrl_notifier.on_ue_context_release_request(ue_context_release_request)); } else { // prepare BearerContextModificationRequest and call e1 notifier 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 c15d7689c7..42a2f2fb25 100644 --- a/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp @@ -10,6 +10,7 @@ #include "pdu_session_resource_setup_routine.h" #include "pdu_session_routine_helpers.h" +#include "srsran/ran/cause/ngap_cause.h" using namespace srsran; using namespace srsran::srs_cu_cp; @@ -309,7 +310,7 @@ void fill_setup_failed_list(cu_cp_pdu_session_resource_setup_response& resp for (const auto& item : setup_msg.pdu_session_res_setup_items) { cu_cp_pdu_session_res_setup_failed_item failed_item; failed_item.pdu_session_id = item.pdu_session_id; - failed_item.unsuccessful_transfer.cause = cause_misc_t::unspecified; + failed_item.unsuccessful_transfer.cause = ngap_cause_misc_t::unspecified; response_msg.pdu_session_res_failed_to_setup_items.emplace(failed_item.pdu_session_id, failed_item); } } @@ -362,7 +363,7 @@ bool handle_procedure_response(cu_cp_pdu_session_resource_setup_response& r // Helper to mark all PDU sessions that were requested to be set up as failed. void mark_all_sessions_as_failed(cu_cp_pdu_session_resource_setup_response& response_msg, const cu_cp_pdu_session_resource_setup_request& setup_msg, - cause_t cause) + e1ap_cause_t cause) { slotted_id_vector failed_list; for (const auto& setup_item : setup_msg.pdu_session_res_setup_items) { @@ -391,7 +392,7 @@ pdu_session_resource_setup_routine::handle_pdu_session_resource_setup_result(boo } else { logger.info("ue={}: \"{}\" failed", setup_msg.ue_index, name()); - mark_all_sessions_as_failed(response_msg, setup_msg, cause_radio_network_t::unspecified); + mark_all_sessions_as_failed(response_msg, setup_msg, e1ap_cause_t{e1ap_cause_radio_network_t::unspecified}); } return response_msg; diff --git a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp index de0b54b944..5780b85104 100644 --- a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp +++ b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp @@ -10,6 +10,7 @@ #include "pdu_session_routine_helpers.h" #include "srsran/asn1/rrc_nr/cell_group_config.h" +#include "srsran/ran/cause/e1ap_cause_converters.h" using namespace srsran; using namespace srsran::srs_cu_cp; @@ -487,7 +488,7 @@ void srsran::srs_cu_cp::update_failed_list( // Add to list taking cause received from CU-UP. cu_cp_pdu_session_res_setup_failed_item failed_item; failed_item.pdu_session_id = e1ap_item.pdu_session_id; - failed_item.unsuccessful_transfer.cause = e1ap_item.cause; + failed_item.unsuccessful_transfer.cause = e1ap_to_ngap_cause(e1ap_item.cause); ngap_failed_list.emplace(failed_item.pdu_session_id, failed_item); } } diff --git a/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp b/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp index 87183db82a..0f3b80a195 100644 --- a/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp +++ b/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp @@ -38,10 +38,6 @@ void reestablishment_context_modification_routine::operator()(coro_context qos_flow_results; }; @@ -39,7 +39,7 @@ struct drb_setup_result { struct pdu_session_setup_result { bool success = false; // True if PDU session could be set up. pdu_session_id_t pdu_session_id = pdu_session_id_t::invalid; // The PDU session ID. - cause_t cause; // Cause if setup was unsuccessful. + e1ap_cause_t cause; // Cause if setup was unsuccessful. up_transport_layer_info gtp_tunnel; optional security_result; std::vector drb_setup_results; @@ -49,7 +49,7 @@ struct pdu_session_setup_result { struct pdu_session_modification_result { bool success = false; // True if PDU session could be set up. pdu_session_id_t pdu_session_id = pdu_session_id_t::invalid; // The PDU session ID. - cause_t cause; // Cause if modification was unsuccessful. + e1ap_cause_t cause; // Cause if modification was unsuccessful. std::vector drb_setup_results; std::vector drb_modification_results; }; diff --git a/lib/cu_up/pdu_session_manager_impl.cpp b/lib/cu_up/pdu_session_manager_impl.cpp index be85645315..86f02ad1c2 100644 --- a/lib/cu_up/pdu_session_manager_impl.cpp +++ b/lib/cu_up/pdu_session_manager_impl.cpp @@ -67,7 +67,7 @@ drb_setup_result pdu_session_manager_impl::handle_drb_to_setup_item(pdu_session& // prepare DRB creation result drb_setup_result drb_result = {}; drb_result.success = false; - drb_result.cause = cause_radio_network_t::unspecified; + drb_result.cause = e1ap_cause_radio_network_t::unspecified; drb_result.drb_id = drb_to_setup.drb_id; // get DRB from list and create context @@ -81,7 +81,7 @@ drb_setup_result pdu_session_manager_impl::handle_drb_to_setup_item(pdu_session& five_qi_t five_qi = drb_to_setup.qos_flow_info_to_be_setup.begin()->qos_flow_level_qos_params.qos_characteristics.get_five_qi(); if (qos_cfg.find(five_qi) == qos_cfg.end()) { - drb_result.cause = cause_radio_network_t::not_supported_5qi_value; + drb_result.cause = e1ap_cause_radio_network_t::not_supported_5qi_value; return drb_result; } @@ -90,7 +90,7 @@ drb_setup_result pdu_session_manager_impl::handle_drb_to_setup_item(pdu_session& // prepare QoS flow creation result qos_flow_setup_result flow_result = {}; flow_result.success = false; - flow_result.cause = cause_radio_network_t::unspecified; + flow_result.cause = e1ap_cause_radio_network_t::unspecified; flow_result.qos_flow_id = qos_flow_info.qos_flow_id; if (!new_session.sdap->is_mapped(qos_flow_info.qos_flow_id) && @@ -109,8 +109,8 @@ drb_setup_result pdu_session_manager_impl::handle_drb_to_setup_item(pdu_session& // fail if mapping already exists flow_result.success = false; flow_result.cause = new_session.sdap->is_mapped(qos_flow_info.qos_flow_id) - ? cause_radio_network_t::multiple_qos_flow_id_instances - : cause_radio_network_t::not_supported_5qi_value; + ? e1ap_cause_radio_network_t::multiple_qos_flow_id_instances + : e1ap_cause_radio_network_t::not_supported_5qi_value; logger.log_error("Cannot overwrite existing mapping for {}", qos_flow_info.qos_flow_id); } @@ -123,7 +123,7 @@ drb_setup_result pdu_session_manager_impl::handle_drb_to_setup_item(pdu_session& logger.log_error( "Failed to create {} for {}: Could not map any QoS flow", drb_to_setup.drb_id, new_session.pdu_session_id); new_session.drbs.erase(drb_to_setup.drb_id); - drb_result.cause = cause_radio_network_t::unspecified; + drb_result.cause = e1ap_cause_radio_network_t::unspecified; drb_result.success = false; return drb_result; } @@ -133,7 +133,7 @@ drb_setup_result pdu_session_manager_impl::handle_drb_to_setup_item(pdu_session& logger.log_error( "Failed to create {} for {}: Could not find 5QI. {}", drb_to_setup.drb_id, new_session.pdu_session_id, five_qi); new_session.drbs.erase(drb_to_setup.drb_id); - drb_result.cause = cause_radio_network_t::not_supported_5qi_value; + drb_result.cause = e1ap_cause_radio_network_t::not_supported_5qi_value; drb_result.success = false; return drb_result; } @@ -225,7 +225,7 @@ pdu_session_setup_result pdu_session_manager_impl::setup_pdu_session(const e1ap_ pdu_session_setup_result pdu_session_result = {}; pdu_session_result.success = false; pdu_session_result.pdu_session_id = session.pdu_session_id; - pdu_session_result.cause = cause_radio_network_t::unspecified; + pdu_session_result.cause = e1ap_cause_radio_network_t::unspecified; if (pdu_sessions.find(session.pdu_session_id) != pdu_sessions.end()) { logger.log_error("PDU Session with {} already exists", session.pdu_session_id); @@ -293,13 +293,13 @@ pdu_session_setup_result pdu_session_manager_impl::setup_pdu_session(const e1ap_ } // Ref: TS 38.463 Sec. 8.3.1.2: - // For each PDU session for which the Security Indication IE is included in the PDU Session Resource To Setup List IE - // of the BEARER CONTEXT SETUP REQUEST message, and the Integrity Protection Indication IE or Confidentiality + // For each PDU session for which the Security Indication IE is included in the PDU Session Resource To Setup List + // IE of the BEARER CONTEXT SETUP REQUEST message, and the Integrity Protection Indication IE or Confidentiality // Protection Indication IE is set to "preferred", then the gNB-CU-UP should, if supported, perform user plane // integrity protection or ciphering, respectively, for the concerned PDU session and shall notify whether it // performed the user plane integrity protection or ciphering by including the Integrity Protection Result IE or - // Confidentiality Protection Result IE, respectively, in the PDU Session Resource Setup List IE of the BEARER CONTEXT - // SETUP RESPONSE message. + // Confidentiality Protection Result IE, respectively, in the PDU Session Resource Setup List IE of the BEARER + // CONTEXT SETUP RESPONSE message. if (security_result_required(session.security_ind)) { pdu_session_result.security_result = security_result_t{}; auto& sec_res = pdu_session_result.security_result.value(); @@ -323,7 +323,7 @@ pdu_session_manager_impl::modify_pdu_session(const e1ap_pdu_session_res_to_modif pdu_session_modification_result pdu_session_result; pdu_session_result.success = false; pdu_session_result.pdu_session_id = session.pdu_session_id; - pdu_session_result.cause = cause_radio_network_t::unspecified; + pdu_session_result.cause = e1ap_cause_radio_network_t::unspecified; if (pdu_sessions.find(session.pdu_session_id) == pdu_sessions.end()) { logger.log_error("PDU Session {} doesn't exists", session.pdu_session_id); @@ -343,7 +343,7 @@ pdu_session_manager_impl::modify_pdu_session(const e1ap_pdu_session_res_to_modif // prepare DRB modification result drb_setup_result drb_result = {}; drb_result.success = false; - drb_result.cause = cause_radio_network_t::unspecified; + drb_result.cause = e1ap_cause_radio_network_t::unspecified; drb_result.drb_id = drb_to_mod.drb_id; // find DRB in PDU session diff --git a/lib/e1ap/common/e1ap_asn1_converters.h b/lib/e1ap/common/e1ap_asn1_converters.h index f141575645..5e630726fb 100644 --- a/lib/e1ap/common/e1ap_asn1_converters.h +++ b/lib/e1ap/common/e1ap_asn1_converters.h @@ -17,7 +17,7 @@ #include "srsran/e1ap/cu_cp/e1ap_cu_cp.h" #include "srsran/e1ap/cu_cp/e1ap_cu_cp_bearer_context_update.h" #include "srsran/ran/bcd_helpers.h" -#include "srsran/ran/cause.h" +#include "srsran/ran/cause/e1ap_cause.h" #include "srsran/ran/qos_prio_level.h" #include "srsran/support/error_handling.h" #include @@ -966,115 +966,25 @@ inline e1ap_pdcp_config e1ap_asn1_to_pdcp_config(asn1::e1ap::pdcp_cfg_s asn1_pdc return pdcp_cfg; } -/// \brief Convert E1AP Cause to \c cause_t type. +/// \brief Convert E1AP Cause to \c e1ap_cause_t type. /// \param e1ap_cause The E1AP Cause. /// \return The cause type. -inline cause_t asn1_to_cause(asn1::e1ap::cause_c e1ap_cause) +inline e1ap_cause_t asn1_to_cause(asn1::e1ap::cause_c e1ap_cause) { - cause_t cause; + e1ap_cause_t cause; switch (e1ap_cause.type()) { case asn1::e1ap::cause_c::types_opts::radio_network: - switch (e1ap_cause.radio_network().value) { - // Common - case asn1::e1ap::cause_radio_network_opts::options::unspecified: - cause = cause_radio_network_t::unspecified; - break; - case asn1::e1ap::cause_radio_network_opts::options::interaction_with_other_proc: - cause = cause_radio_network_t::interaction_with_other_proc; - break; - case asn1::e1ap::cause_radio_network_opts::options::res_not_available_for_the_slice: - cause = cause_radio_network_t::res_not_available_for_the_slice; - break; - // Common for E1AP and NGAP - case asn1::e1ap::cause_radio_network_opts::options::not_supported_5qi_value: - cause = cause_radio_network_t::not_supported_5qi_value; - break; - case asn1::e1ap::cause_radio_network_opts::options::up_integrity_protection_not_possible: - cause = cause_radio_network_t::up_integrity_protection_not_possible; - break; - case asn1::e1ap::cause_radio_network_opts::options::up_confidentiality_protection_not_possible: - cause = cause_radio_network_t::up_confidentiality_protection_not_possible; - break; - case asn1::e1ap::cause_radio_network_opts::options::multiple_pdu_session_id_instances: - cause = cause_radio_network_t::multiple_pdu_session_id_instances; - break; - case asn1::e1ap::cause_radio_network_opts::options::unknown_pdu_session_id: - cause = cause_radio_network_t::unknown_pdu_session_id; - break; - case asn1::e1ap::cause_radio_network_opts::options::multiple_qos_flow_id_instances: - cause = cause_radio_network_t::multiple_qos_flow_id_instances; - break; - case asn1::e1ap::cause_radio_network_opts::options::invalid_qos_combination: - cause = cause_radio_network_t::invalid_qos_combination; - break; - // Common for E1AP and F1AP - case asn1::e1ap::cause_radio_network_opts::options::not_supported_qci_value: - cause = cause_radio_network_t::not_supported_qci_value; - break; - case asn1::e1ap::cause_radio_network_opts::options::multiple_drb_id_instances: - cause = cause_radio_network_t::multiple_drb_id_instances; - break; - case asn1::e1ap::cause_radio_network_opts::options::unknown_drb_id: - cause = cause_radio_network_t::unknown_drb_id; - break; - case asn1::e1ap::cause_radio_network_opts::options::proc_cancelled: - cause = cause_radio_network_t::proc_cancelled; - break; - case asn1::e1ap::cause_radio_network_opts::options::normal_release: - cause = cause_radio_network_t::normal_release; - break; - case asn1::e1ap::cause_radio_network_opts::options::no_radio_res_available: - cause = cause_radio_network_t::no_radio_res_available; - break; - case asn1::e1ap::cause_radio_network_opts::options::action_desirable_for_radio_reasons: - cause = cause_radio_network_t::action_desirable_for_radio_reasons; - break; - case asn1::e1ap::cause_radio_network_opts::options::release_due_to_pre_emption: - cause = cause_radio_network_t::release_due_to_pre_emption; - break; - case asn1::e1ap::cause_radio_network_opts::options::npn_not_supported: - cause = cause_radio_network_t::npn_not_supported; - break; - case asn1::e1ap::cause_radio_network_opts::options::existing_meas_id: - cause = cause_radio_network_t::existing_meas_id; - break; - case asn1::e1ap::cause_radio_network_opts::options::meas_temporarily_not_available: - cause = cause_radio_network_t::meas_temporarily_not_available; - break; - case asn1::e1ap::cause_radio_network_opts::options::meas_not_supported_for_the_obj: - cause = cause_radio_network_t::meas_not_supported_for_the_obj; - break; - // E1AP - default: - cause = - static_cast(e1ap_cause.radio_network().value + E1AP_RADIO_NETWORK_CAUSE_OFFSET); - } + cause = static_cast(e1ap_cause.radio_network().value); break; case asn1::e1ap::cause_c::types_opts::transport: - // The mapping is not 1:1, so we need to handle most cases separately - switch (e1ap_cause.transport().value) { - case asn1::e1ap::cause_transport_opts::transport_res_unavailable: - cause = cause_transport_t::transport_res_unavailable; - break; - case asn1::e1ap::cause_transport_opts::unspecified: - cause = cause_transport_t::unspecified; - break; - default: - cause = static_cast(e1ap_cause.transport().value); - } + cause = static_cast(e1ap_cause.transport().value); break; case asn1::e1ap::cause_c::types_opts::protocol: - // The mapping is 1:1 so we can directly convert the value cause = static_cast(e1ap_cause.protocol().value); break; case asn1::e1ap::cause_c::types_opts::misc: - // The mapping is not 1:1, so we need to handle the unspecified case separately - if (e1ap_cause.misc().value == asn1::e1ap::cause_misc_opts::unspecified) { - cause = cause_misc_t::unspecified; - } else { - cause = static_cast(e1ap_cause.misc().value); - } + cause = static_cast(e1ap_cause.misc().value); break; default: report_fatal_error("Cannot convert E1AP ASN.1 cause {} to common type", e1ap_cause.type()); @@ -1083,121 +993,29 @@ inline cause_t asn1_to_cause(asn1::e1ap::cause_c e1ap_cause) return cause; } -/// \brief Convert \c cause_t type to E1AP ASN.1 cause. -/// \param cause The cause_t type. +/// \brief Convert \c e1ap_cause_t type to E1AP ASN.1 cause. +/// \param cause The e1ap_cause_t type. /// \return The E1AP ASN.1 cause. -inline asn1::e1ap::cause_c cause_to_e1ap_asn1(cause_t cause) +inline asn1::e1ap::cause_c cause_to_asn1(e1ap_cause_t cause) { - asn1::e1ap::cause_c e1ap_cause; - - if (variant_holds_alternative(cause)) { - // Convert E1AP types - if (static_cast(variant_get(cause)) >= E1AP_RADIO_NETWORK_CAUSE_OFFSET) { - e1ap_cause.set_radio_network() = static_cast( - static_cast(variant_get(cause)) - E1AP_RADIO_NETWORK_CAUSE_OFFSET); - } else { - switch (variant_get(cause)) { - // Common - case cause_radio_network_t::interaction_with_other_proc: - e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::interaction_with_other_proc; - break; - case cause_radio_network_t::res_not_available_for_the_slice: - e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::res_not_available_for_the_slice; - break; - // Common for E1AP and NGAP - case cause_radio_network_t::not_supported_5qi_value: - e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::not_supported_5qi_value; - break; - case cause_radio_network_t::up_integrity_protection_not_possible: - e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::up_integrity_protection_not_possible; - break; - case cause_radio_network_t::up_confidentiality_protection_not_possible: - e1ap_cause.set_radio_network() = - asn1::e1ap::cause_radio_network_opts::up_confidentiality_protection_not_possible; - break; - case cause_radio_network_t::multiple_pdu_session_id_instances: - e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::multiple_pdu_session_id_instances; - break; - case cause_radio_network_t::unknown_pdu_session_id: - e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::unknown_pdu_session_id; - break; - case cause_radio_network_t::multiple_qos_flow_id_instances: - e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::multiple_qos_flow_id_instances; - break; - case cause_radio_network_t::invalid_qos_combination: - e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::invalid_qos_combination; - break; - // Common for E1AP and F1AP - case cause_radio_network_t::not_supported_qci_value: - e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::not_supported_qci_value; - break; - case cause_radio_network_t::multiple_drb_id_instances: - e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::multiple_drb_id_instances; - break; - case cause_radio_network_t::unknown_drb_id: - e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::unknown_drb_id; - break; - case cause_radio_network_t::proc_cancelled: - e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::proc_cancelled; - break; - case cause_radio_network_t::normal_release: - e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::normal_release; - break; - case cause_radio_network_t::no_radio_res_available: - e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::no_radio_res_available; - break; - case cause_radio_network_t::action_desirable_for_radio_reasons: - e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::action_desirable_for_radio_reasons; - break; - case cause_radio_network_t::release_due_to_pre_emption: - e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::release_due_to_pre_emption; - break; - case cause_radio_network_t::npn_not_supported: - e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::npn_not_supported; - break; - case cause_radio_network_t::existing_meas_id: - e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::existing_meas_id; - break; - case cause_radio_network_t::meas_temporarily_not_available: - e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::meas_temporarily_not_available; - break; - case cause_radio_network_t::meas_not_supported_for_the_obj: - e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::meas_not_supported_for_the_obj; - break; - // E1AP - default: - e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::unspecified; - } - } - } else if (variant_holds_alternative(cause)) { - // The mapping is not 1:1, so we need to handle most cases separately - switch (variant_get(cause)) { - case cause_transport_t::transport_res_unavailable: - e1ap_cause.set_transport() = asn1::e1ap::cause_transport_opts::transport_res_unavailable; - break; - case cause_transport_t::unspecified: - e1ap_cause.set_transport() = asn1::e1ap::cause_transport_opts::unspecified; - break; - default: - e1ap_cause.set_transport() = - static_cast(variant_get(cause)); - } + asn1::e1ap::cause_c asn1_cause; + + if (variant_holds_alternative(cause)) { + asn1_cause.set_radio_network() = + static_cast(variant_get(cause)); + } else if (variant_holds_alternative(cause)) { + asn1_cause.set_transport() = + static_cast(variant_get(cause)); } else if (variant_holds_alternative(cause)) { - // The mapping is 1:1 so we can directly convert the value - e1ap_cause.set_protocol() = + asn1_cause.set_protocol() = static_cast(variant_get(cause)); } else if (variant_holds_alternative(cause)) { - // The mapping is not 1:1, so we need to handle the unspecified case separately - if (variant_get(cause) == cause_misc_t::unspecified) { - e1ap_cause.set_misc() = asn1::e1ap::cause_misc_opts::unspecified; - } else { - e1ap_cause.set_misc() = static_cast(variant_get(cause)); - } + asn1_cause.set_misc() = static_cast(variant_get(cause)); } else { - report_fatal_error("Cannot convert cause to E1AP type"); + report_fatal_error("Cannot convert cause to E1AP type: {}", cause); } - return e1ap_cause; + return asn1_cause; } /// \brief Convert E1AP NG DL UP Unchanged to its boolean representation @@ -1500,7 +1318,7 @@ inline void e1ap_drb_failed_item_list_to_asn1( // Add DRB ID asn1_drb_failed_item.drb_id = drb_id_to_uint(drb_failed_item.drb_id); // Add Cause - asn1_drb_failed_item.cause = cause_to_e1ap_asn1(drb_failed_item.cause); + asn1_drb_failed_item.cause = cause_to_asn1(drb_failed_item.cause); asn1_drb_item_list.push_back(asn1_drb_failed_item); } } diff --git a/lib/e1ap/cu_cp/e1ap_cu_cp_asn1_helpers.h b/lib/e1ap/cu_cp/e1ap_cu_cp_asn1_helpers.h index 5a5c64f1e2..f0f38b97c2 100644 --- a/lib/e1ap/cu_cp/e1ap_cu_cp_asn1_helpers.h +++ b/lib/e1ap/cu_cp/e1ap_cu_cp_asn1_helpers.h @@ -943,7 +943,7 @@ inline void fill_e1ap_bearer_context_modification_response( inline void fill_asn1_bearer_context_release_command(asn1::e1ap::bearer_context_release_cmd_s& asn1_command, const e1ap_bearer_context_release_command& command) { - asn1_command->cause = cause_to_e1ap_asn1(command.cause); + asn1_command->cause = cause_to_asn1(command.cause); } } // namespace srs_cu_cp diff --git a/lib/e1ap/cu_cp/e1ap_cu_cp_impl.cpp b/lib/e1ap/cu_cp/e1ap_cu_cp_impl.cpp index 41148c56c7..03c1cf2563 100644 --- a/lib/e1ap/cu_cp/e1ap_cu_cp_impl.cpp +++ b/lib/e1ap/cu_cp/e1ap_cu_cp_impl.cpp @@ -12,7 +12,7 @@ #include "../common/e1ap_asn1_helpers.h" #include "e1ap_cu_cp_asn1_helpers.h" #include "srsran/asn1/e1ap/e1ap.h" -#include "srsran/ran/cause.h" +#include "srsran/ran/cause/e1ap_cause.h" using namespace srsran; using namespace asn1::e1ap; @@ -64,7 +64,7 @@ void e1ap_cu_cp_impl::handle_cu_up_e1_setup_response(const cu_up_e1_setup_respon e1ap_msg.pdu.unsuccessful_outcome().load_info_obj(ASN1_E1AP_ID_GNB_CU_UP_E1_SETUP); e1ap_msg.pdu.unsuccessful_outcome().value.gnb_cu_up_e1_setup_fail(); auto& setup_fail = e1ap_msg.pdu.unsuccessful_outcome().value.gnb_cu_up_e1_setup_fail(); - setup_fail->cause = cause_to_e1ap_asn1(msg.cause.value()); + setup_fail->cause = cause_to_asn1(msg.cause.value()); // set values handled by E1 setup_fail->transaction_id = current_transaction_id; diff --git a/lib/e1ap/cu_up/e1ap_cu_up_asn1_helpers.h b/lib/e1ap/cu_up/e1ap_cu_up_asn1_helpers.h index 5948d1e7a7..a63e0dfdcd 100644 --- a/lib/e1ap/cu_up/e1ap_cu_up_asn1_helpers.h +++ b/lib/e1ap/cu_up/e1ap_cu_up_asn1_helpers.h @@ -361,7 +361,7 @@ inline void fill_asn1_bearer_context_setup_response(asn1::e1ap::sys_bearer_conte for (const auto& failed_item : response.pdu_session_resource_failed_list) { asn1::e1ap::pdu_session_res_failed_item_s asn1_failed_item; asn1_failed_item.pdu_session_id = pdu_session_id_to_uint(failed_item.pdu_session_id); - asn1_failed_item.cause = cause_to_e1ap_asn1(failed_item.cause); + asn1_failed_item.cause = cause_to_asn1(failed_item.cause); asn1_bearer_context_setup_response.pdu_session_res_failed_list.push_back(asn1_failed_item); } @@ -724,7 +724,7 @@ inline void fill_asn1_bearer_context_modification_response(asn1::e1ap::sys_beare for (const auto& res_failed_mod_item : response.pdu_session_resource_failed_list) { asn1::e1ap::pdu_session_res_failed_mod_item_s asn1_res_failed_mod_item; asn1_res_failed_mod_item.pdu_session_id = pdu_session_id_to_uint(res_failed_mod_item.pdu_session_id); - asn1_res_failed_mod_item.cause = cause_to_e1ap_asn1(res_failed_mod_item.cause); + asn1_res_failed_mod_item.cause = cause_to_asn1(res_failed_mod_item.cause); asn1_bearer_context_modification_response.pdu_session_res_failed_mod_list.push_back(asn1_res_failed_mod_item); } @@ -847,7 +847,7 @@ inline void fill_asn1_bearer_context_modification_response(asn1::e1ap::sys_beare for (const auto& res_failed_to_modify_item : response.pdu_session_resource_failed_to_modify_list) { asn1::e1ap::pdu_session_res_failed_to_modify_item_s asn1_res_failed_to_modify_item; asn1_res_failed_to_modify_item.pdu_session_id = pdu_session_id_to_uint(res_failed_to_modify_item.pdu_session_id); - asn1_res_failed_to_modify_item.cause = cause_to_e1ap_asn1(res_failed_to_modify_item.cause); + asn1_res_failed_to_modify_item.cause = cause_to_asn1(res_failed_to_modify_item.cause); asn1_bearer_context_modification_response.pdu_session_res_failed_to_modify_list.push_back( asn1_res_failed_to_modify_item); diff --git a/lib/e1ap/cu_up/e1ap_cu_up_impl.cpp b/lib/e1ap/cu_up/e1ap_cu_up_impl.cpp index 33d19a7e04..4ef71eb40e 100644 --- a/lib/e1ap/cu_up/e1ap_cu_up_impl.cpp +++ b/lib/e1ap/cu_up/e1ap_cu_up_impl.cpp @@ -240,7 +240,7 @@ void e1ap_cu_up_impl::handle_bearer_context_setup_request(const asn1::e1ap::bear connection_handler.on_new_message(e1ap_msg); } else { e1ap_msg.pdu.unsuccessful_outcome().value.bearer_context_setup_fail()->cause = - cause_to_e1ap_asn1(bearer_context_setup_response_msg.cause.value()); + cause_to_asn1(bearer_context_setup_response_msg.cause.value()); // send response ue_ctxt.logger.log_debug("Sending BearerContextSetupFailure"); @@ -311,7 +311,7 @@ void e1ap_cu_up_impl::handle_bearer_context_modification_request(const asn1::e1a connection_handler.on_new_message(e1ap_msg); } else { e1ap_msg.pdu.unsuccessful_outcome().value.bearer_context_mod_fail()->cause = - cause_to_e1ap_asn1(bearer_context_mod_response_msg.cause.value()); + cause_to_asn1(bearer_context_mod_response_msg.cause.value()); // send response ue_ctxt.logger.log_debug("Sending BearerContextModificationFailure"); diff --git a/lib/f1ap/cu_cp/f1ap_asn1_converters.h b/lib/f1ap/cu_cp/f1ap_asn1_converters.h index 96b0a48149..a71f427cfd 100644 --- a/lib/f1ap/cu_cp/f1ap_asn1_converters.h +++ b/lib/f1ap/cu_cp/f1ap_asn1_converters.h @@ -16,7 +16,7 @@ #include "srsran/asn1/f1ap/f1ap_ies.h" #include "srsran/cu_cp/cu_cp_types.h" #include "srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h" -#include "srsran/ran/cause.h" +#include "srsran/ran/cause/f1ap_cause.h" #include "srsran/ran/nr_cgi.h" #include #include @@ -24,201 +24,56 @@ namespace srsran { namespace srs_cu_cp { -/// \brief Convert F1AP ASN.1 Cause to \c cause_t type. -/// \param f1ap_cause The F1AP Cause. -/// \return The cause_t type. -inline cause_t asn1_to_cause(asn1::f1ap::cause_c f1ap_cause) +/// \brief Convert F1AP ASN.1 Cause to \c f1ap_cause_t type. +/// \param asn1_cause The F1AP Cause. +/// \return The f1ap_cause_t type. +inline f1ap_cause_t asn1_to_cause(asn1::f1ap::cause_c asn1_cause) { - cause_t cause; + f1ap_cause_t cause; - switch (f1ap_cause.type()) { + switch (asn1_cause.type()) { case asn1::f1ap::cause_c::types_opts::radio_network: - switch (f1ap_cause.radio_network().value) { - // Common - case asn1::f1ap::cause_radio_network_opts::options::unspecified: - cause = cause_radio_network_t::unspecified; - break; - case asn1::f1ap::cause_radio_network_opts::options::interaction_with_other_proc: - cause = cause_radio_network_t::interaction_with_other_proc; - break; - case asn1::f1ap::cause_radio_network_opts::options::res_not_available_for_the_slice: - cause = cause_radio_network_t::res_not_available_for_the_slice; - break; - // Common for F1AP and NGAP - case asn1::f1ap::cause_radio_network_opts::options::cell_not_available: - cause = cause_radio_network_t::cell_not_available; - break; - // Common for F1AP and E1AP - case asn1::f1ap::cause_radio_network_opts::options::not_supported_qci_value: - cause = cause_radio_network_t::not_supported_qci_value; - break; - case asn1::f1ap::cause_radio_network_opts::options::multiple_drb_id_instances: - cause = cause_radio_network_t::multiple_drb_id_instances; - break; - case asn1::f1ap::cause_radio_network_opts::options::unknown_drb_id: - cause = cause_radio_network_t::unknown_drb_id; - break; - case asn1::f1ap::cause_radio_network_opts::options::proc_cancelled: - cause = cause_radio_network_t::proc_cancelled; - break; - case asn1::f1ap::cause_radio_network_opts::options::normal_release: - cause = cause_radio_network_t::normal_release; - break; - case asn1::f1ap::cause_radio_network_opts::options::no_radio_res_available: - cause = cause_radio_network_t::no_radio_res_available; - break; - case asn1::f1ap::cause_radio_network_opts::options::action_desirable_for_radio_reasons: - cause = cause_radio_network_t::action_desirable_for_radio_reasons; - break; - case asn1::f1ap::cause_radio_network_opts::options::release_due_to_pre_emption: - cause = cause_radio_network_t::release_due_to_pre_emption; - break; - case asn1::f1ap::cause_radio_network_opts::options::npn_not_supported: - cause = cause_radio_network_t::npn_not_supported; - break; - case asn1::f1ap::cause_radio_network_opts::options::existing_meas_id: - cause = cause_radio_network_t::existing_meas_id; - break; - case asn1::f1ap::cause_radio_network_opts::options::meas_temporarily_not_available: - cause = cause_radio_network_t::meas_temporarily_not_available; - break; - case asn1::f1ap::cause_radio_network_opts::options::meas_not_supported_for_the_obj: - cause = cause_radio_network_t::meas_not_supported_for_the_obj; - break; - // F1AP - default: - cause = static_cast(f1ap_cause.radio_network() + F1AP_RADIO_NETWORK_CAUSE_OFFSET); - } + cause = static_cast(asn1_cause.radio_network().value); break; case asn1::f1ap::cause_c::types_opts::transport: - // The mapping is not 1:1, so we need to handle most cases separately - switch (f1ap_cause.transport().value) { - case asn1::f1ap::cause_transport_opts::transport_res_unavailable: - cause = cause_transport_t::transport_res_unavailable; - break; - case asn1::f1ap::cause_transport_opts::unspecified: - cause = cause_transport_t::unspecified; - break; - default: - cause = static_cast(f1ap_cause.transport().value); - } + cause = static_cast(asn1_cause.transport().value); break; case asn1::f1ap::cause_c::types_opts::protocol: - // The mapping is 1:1 so we can directly convert the value - cause = static_cast(f1ap_cause.protocol().value); + cause = static_cast(asn1_cause.protocol().value); break; case asn1::f1ap::cause_c::types_opts::misc: - // The mapping is not 1:1, so we need to handle the unspecified case separately - if (f1ap_cause.misc().value == asn1::f1ap::cause_misc_opts::unspecified) { - cause = cause_misc_t::unspecified; - } else { - cause = static_cast(f1ap_cause.misc().value); - } + cause = static_cast(asn1_cause.misc().value); break; default: - report_fatal_error("Cannot convert F1AP ASN.1 cause {} to common type", f1ap_cause.type()); + report_fatal_error("Cannot convert F1AP ASN.1 cause {} to common type", asn1_cause.type()); } return cause; } -/// \brief Convert \c cause_t type to F1AP cause. -/// \param cause The cause_t type. +/// \brief Convert \c f1ap_cause_t type to F1AP cause. +/// \param cause The f1ap_cause_t type. /// \return The F1AP cause. -inline asn1::f1ap::cause_c cause_to_f1ap_asn1(cause_t cause) +inline asn1::f1ap::cause_c cause_to_asn1(f1ap_cause_t cause) { - asn1::f1ap::cause_c f1ap_cause; - - if (variant_holds_alternative(cause)) { - // Convert F1AP types - if (static_cast(variant_get(cause)) >= F1AP_RADIO_NETWORK_CAUSE_OFFSET && - static_cast(variant_get(cause)) < E1AP_RADIO_NETWORK_CAUSE_OFFSET) { - f1ap_cause.set_radio_network() = static_cast( - static_cast(variant_get(cause)) - F1AP_RADIO_NETWORK_CAUSE_OFFSET); - } else { - switch (variant_get(cause)) { - // Common - case cause_radio_network_t::interaction_with_other_proc: - f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::interaction_with_other_proc; - break; - case cause_radio_network_t::res_not_available_for_the_slice: - f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::res_not_available_for_the_slice; - break; - // Common for F1AP and NGAP - case cause_radio_network_t::cell_not_available: - f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::cell_not_available; - break; - // Common for F1AP and E1AP - case cause_radio_network_t::not_supported_qci_value: - f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::not_supported_qci_value; - break; - case cause_radio_network_t::multiple_drb_id_instances: - f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::multiple_drb_id_instances; - break; - case cause_radio_network_t::unknown_drb_id: - f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::unknown_drb_id; - break; - case cause_radio_network_t::proc_cancelled: - f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::proc_cancelled; - break; - case cause_radio_network_t::normal_release: - f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::normal_release; - break; - case cause_radio_network_t::no_radio_res_available: - f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::no_radio_res_available; - break; - case cause_radio_network_t::action_desirable_for_radio_reasons: - f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::action_desirable_for_radio_reasons; - break; - case cause_radio_network_t::release_due_to_pre_emption: - f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::release_due_to_pre_emption; - break; - case cause_radio_network_t::npn_not_supported: - f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::npn_not_supported; - break; - case cause_radio_network_t::existing_meas_id: - f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::existing_meas_id; - break; - case cause_radio_network_t::meas_temporarily_not_available: - f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::meas_temporarily_not_available; - break; - case cause_radio_network_t::meas_not_supported_for_the_obj: - f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::meas_not_supported_for_the_obj; - break; - // F1AP - default: - f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::unspecified; - } - } - } else if (variant_holds_alternative(cause)) { - // The mapping is not 1:1, so we need to handle most cases separately - switch (variant_get(cause)) { - case cause_transport_t::transport_res_unavailable: - f1ap_cause.set_transport() = asn1::f1ap::cause_transport_opts::transport_res_unavailable; - break; - case cause_transport_t::unspecified: - f1ap_cause.set_transport() = asn1::f1ap::cause_transport_opts::unspecified; - break; - default: - f1ap_cause.set_transport() = - static_cast(variant_get(cause)); - } + asn1::f1ap::cause_c asn1_cause; + + if (variant_holds_alternative(cause)) { + asn1_cause.set_radio_network() = + static_cast(variant_get(cause)); + } else if (variant_holds_alternative(cause)) { + asn1_cause.set_transport() = + static_cast(variant_get(cause)); } else if (variant_holds_alternative(cause)) { - // The mapping is 1:1 so we can directly convert the value - f1ap_cause.set_protocol() = + asn1_cause.set_protocol() = static_cast(variant_get(cause)); } else if (variant_holds_alternative(cause)) { - // The mapping is not 1:1, so we need to handle the unspecified case separately - if (variant_get(cause) == cause_misc_t::unspecified) { - f1ap_cause.set_misc() = asn1::f1ap::cause_misc_opts::unspecified; - } else { - f1ap_cause.set_misc() = static_cast(variant_get(cause)); - } + asn1_cause.set_misc() = static_cast(variant_get(cause)); } else { - report_fatal_error("Cannot convert cause to F1AP type"); + report_fatal_error("Cannot convert cause to F1AP type: {}", cause); } - return f1ap_cause; + return asn1_cause; } /// \brief Convert F1AP NRCGI to NR Cell Identity. diff --git a/lib/f1ap/cu_cp/procedures/f1_setup_procedure.cpp b/lib/f1ap/cu_cp/procedures/f1_setup_procedure.cpp index f6d79acbbf..0c812b0942 100644 --- a/lib/f1ap/cu_cp/procedures/f1_setup_procedure.cpp +++ b/lib/f1ap/cu_cp/procedures/f1_setup_procedure.cpp @@ -15,7 +15,7 @@ #include "srsran/asn1/f1ap/f1ap_pdu_contents.h" #include "srsran/f1ap/common/f1ap_message.h" #include "srsran/f1ap/cu_cp/du_setup_notifier.h" -#include "srsran/ran/cause.h" +#include "srsran/ran/cause/f1ap_cause.h" using namespace srsran; using namespace srs_cu_cp; @@ -186,7 +186,7 @@ void srsran::srs_cu_cp::handle_f1_setup_procedure(const asn1::f1ap::f1_setup_req // Failed to setup DU case. auto& fail_resp = variant_get(request_outcome.result); logger.warning("Rejecting F1 Setup Request. Cause: {}", fail_resp.cause_str); - f1ap_msg = create_f1_setup_reject(request, cause_to_f1ap_asn1(fail_resp.cause)); + f1ap_msg = create_f1_setup_reject(request, cause_to_asn1(fail_resp.cause)); } else { // DU has been accepted. f1ap_msg = create_f1_setup_response(request, variant_get(request_outcome.result)); diff --git a/lib/f1ap/cu_cp/procedures/ue_context_modification_procedure.cpp b/lib/f1ap/cu_cp/procedures/ue_context_modification_procedure.cpp index ce0a8a622e..ca2df0984d 100644 --- a/lib/f1ap/cu_cp/procedures/ue_context_modification_procedure.cpp +++ b/lib/f1ap/cu_cp/procedures/ue_context_modification_procedure.cpp @@ -12,7 +12,7 @@ #include "../../common/asn1_helpers.h" #include "../f1ap_asn1_helpers.h" #include "srsran/f1ap/common/f1ap_message.h" -#include "srsran/ran/cause.h" +#include "srsran/ran/cause/ngap_cause.h" using namespace srsran; using namespace srsran::srs_cu_cp; diff --git a/lib/f1ap/cu_cp/procedures/ue_context_release_procedure.cpp b/lib/f1ap/cu_cp/procedures/ue_context_release_procedure.cpp index db3d4e6268..14c9578b3b 100644 --- a/lib/f1ap/cu_cp/procedures/ue_context_release_procedure.cpp +++ b/lib/f1ap/cu_cp/procedures/ue_context_release_procedure.cpp @@ -25,7 +25,7 @@ ue_context_release_procedure::ue_context_release_procedure(const f1ap_ue_context { command->gnb_cu_ue_f1ap_id = gnb_cu_ue_f1ap_id_to_uint(ue_ctxt.ue_ids.cu_ue_f1ap_id); command->gnb_du_ue_f1ap_id = gnb_du_ue_f1ap_id_to_uint(ue_ctxt.ue_ids.du_ue_f1ap_id); - command->cause = cause_to_f1ap_asn1(cmd_.cause); + command->cause = cause_to_asn1(cmd_.cause); if (!cmd_.rrc_release_pdu.empty()) { command->rrc_container_present = true; command->rrc_container = cmd_.rrc_release_pdu.copy(); diff --git a/lib/ngap/ngap_asn1_converters.h b/lib/ngap/ngap_asn1_converters.h index 215bbef231..a48fa03ff4 100644 --- a/lib/ngap/ngap_asn1_converters.h +++ b/lib/ngap/ngap_asn1_converters.h @@ -16,7 +16,7 @@ #include "srsran/cu_cp/cu_cp_types.h" #include "srsran/ngap/ngap_handover.h" #include "srsran/ran/bcd_helpers.h" -#include "srsran/ran/cause.h" +#include "srsran/ran/cause/ngap_cause.h" #include "srsran/ran/cu_types.h" #include "srsran/ran/lcid.h" #include "srsran/ran/up_transport_layer_info.h" @@ -109,161 +109,58 @@ cu_cp_qos_flow_per_tnl_info_to_ngap_qos_flow_per_tnl_info(const cu_cp_qos_flow_p return ngap_qos_flow_info; } -/// \brief Convert \c cause_t type to NGAP cause. -/// \param cause The cause_t type. +/// \brief Convert \c ngap_cause_t type to NGAP cause. +/// \param cause The ngap_cause_t type. /// \return The NGAP cause. -inline asn1::ngap::cause_c cause_to_ngap_asn1(cause_t cause) +inline asn1::ngap::cause_c cause_to_asn1(ngap_cause_t cause) { - asn1::ngap::cause_c ngap_cause; - - if (variant_holds_alternative(cause)) { - // Convert NGAP types - if (static_cast(variant_get(cause)) >= NGAP_RADIO_NETWORK_CAUSE_OFFSET && - static_cast(variant_get(cause)) < F1AP_RADIO_NETWORK_CAUSE_OFFSET) { - ngap_cause.set_radio_network() = static_cast( - static_cast(variant_get(cause)) - NGAP_RADIO_NETWORK_CAUSE_OFFSET); - } else { - switch (variant_get(cause)) { - // Common type - case cause_radio_network_t::interaction_with_other_proc: - ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::interaction_with_other_proc; - break; - case cause_radio_network_t::res_not_available_for_the_slice: - ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::res_not_available_for_the_slice; - break; - // Common for NGAP and F1AP - case cause_radio_network_t::cell_not_available: - ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::cell_not_available; - break; - // Common for NGAP and E1AP - case cause_radio_network_t::not_supported_5qi_value: - ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::not_supported_5qi_value; - break; - case cause_radio_network_t::up_integrity_protection_not_possible: - ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::up_integrity_protection_not_possible; - break; - case cause_radio_network_t::up_confidentiality_protection_not_possible: - ngap_cause.set_radio_network() = - asn1::ngap::cause_radio_network_opts::up_confidentiality_protection_not_possible; - break; - case cause_radio_network_t::multiple_pdu_session_id_instances: - ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::multiple_pdu_session_id_instances; - break; - case cause_radio_network_t::unknown_pdu_session_id: - ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::unknown_pdu_session_id; - break; - case cause_radio_network_t::multiple_qos_flow_id_instances: - ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::multiple_qos_flow_id_instances; - break; - case cause_radio_network_t::invalid_qos_combination: - ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::invalid_qos_combination; - break; - // F1AP to NGAP conversion - case cause_radio_network_t::rl_fail_rlc: - ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::radio_conn_with_ue_lost; - break; - case cause_radio_network_t::rl_fail_others: - ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::radio_conn_with_ue_lost; - break; - // E1AP to NGAP conversion - case cause_radio_network_t::encryption_algorithms_not_supported: - case cause_radio_network_t::integrity_protection_algorithms_not_supported: - ngap_cause.set_radio_network() = - asn1::ngap::cause_radio_network_opts::encryption_and_or_integrity_protection_algorithms_not_supported; - break; - // NGAP - default: - ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::unspecified; - } - } - } else if (variant_holds_alternative(cause)) { - ngap_cause.set_transport() = - static_cast(variant_get(cause)); + asn1::ngap::cause_c asn1_cause; + + if (variant_holds_alternative(cause)) { + asn1_cause.set_radio_network() = + static_cast(variant_get(cause)); + } else if (variant_holds_alternative(cause)) { + asn1_cause.set_transport() = + static_cast(variant_get(cause)); } else if (variant_holds_alternative(cause)) { - ngap_cause.set_nas() = static_cast(variant_get(cause)); + asn1_cause.set_nas() = static_cast(variant_get(cause)); } else if (variant_holds_alternative(cause)) { - ngap_cause.set_protocol() = + asn1_cause.set_protocol() = static_cast(variant_get(cause)); - } else if (variant_holds_alternative(cause)) { - ngap_cause.set_misc() = static_cast(variant_get(cause)); + } else if (variant_holds_alternative(cause)) { + asn1_cause.set_misc() = static_cast(variant_get(cause)); } else { - report_fatal_error("Cannot convert cause to NGAP type"); + report_fatal_error("Cannot convert cause to NGAP type:{}", cause); } - return ngap_cause; + return asn1_cause; } -/// \brief Convert NGAP ASN1 cause to \c cause_t type. -/// \param ngap_cause The ASN1 NGAP cause. -/// \return The cause_t type. -inline cause_t asn1_to_cause(asn1::ngap::cause_c ngap_cause) +/// \brief Convert NGAP ASN1 cause to \c ngap_cause_t type. +/// \param asn1_cause The ASN1 NGAP cause. +/// \return The ngap_cause_t type. +inline ngap_cause_t asn1_to_cause(asn1::ngap::cause_c asn1_cause) { - cause_t cause; + ngap_cause_t cause; - switch (ngap_cause.type()) { + switch (asn1_cause.type()) { case asn1::ngap::cause_c::types_opts::radio_network: - switch (ngap_cause.radio_network().value) { - // Common - case asn1::ngap::cause_radio_network_opts::options::unspecified: - cause = cause_radio_network_t::unspecified; - break; - case asn1::ngap::cause_radio_network_opts::options::interaction_with_other_proc: - cause = cause_radio_network_t::interaction_with_other_proc; - break; - case asn1::ngap::cause_radio_network_opts::options::res_not_available_for_the_slice: - cause = cause_radio_network_t::res_not_available_for_the_slice; - break; - // Common for NGAP and F1AP - case asn1::ngap::cause_radio_network_opts::options::cell_not_available: - cause = cause_radio_network_t::cell_not_available; - break; - // Common for NGAP and E1AP - case asn1::ngap::cause_radio_network_opts::options::not_supported_5qi_value: - cause = cause_radio_network_t::not_supported_5qi_value; - break; - case asn1::ngap::cause_radio_network_opts::options::up_integrity_protection_not_possible: - cause = cause_radio_network_t::up_integrity_protection_not_possible; - break; - case asn1::ngap::cause_radio_network_opts::options::up_confidentiality_protection_not_possible: - cause = cause_radio_network_t::up_confidentiality_protection_not_possible; - break; - case asn1::ngap::cause_radio_network_opts::options::multiple_pdu_session_id_instances: - cause = cause_radio_network_t::multiple_pdu_session_id_instances; - break; - case asn1::ngap::cause_radio_network_opts::options::unknown_pdu_session_id: - cause = cause_radio_network_t::unknown_pdu_session_id; - break; - case asn1::ngap::cause_radio_network_opts::options::multiple_qos_flow_id_instances: - cause = cause_radio_network_t::multiple_qos_flow_id_instances; - break; - case asn1::ngap::cause_radio_network_opts::options::invalid_qos_combination: - cause = cause_radio_network_t::invalid_qos_combination; - break; - // NGAP - default: - cause = - static_cast(ngap_cause.radio_network().value + NGAP_RADIO_NETWORK_CAUSE_OFFSET); - } + cause = static_cast(asn1_cause.radio_network().value); break; case asn1::ngap::cause_c::types_opts::transport: - // The mapping is not 1:1, so we need to handle some cases separately - if (ngap_cause.transport().value == asn1::ngap::cause_transport_opts::options::transport_res_unavailable) { - cause = cause_transport_t::transport_res_unavailable; - } else { - cause = cause_transport_t::unspecified; - } + cause = static_cast(asn1_cause.transport().value); break; case asn1::ngap::cause_c::types_opts::nas: - cause = static_cast(ngap_cause.nas().value); + cause = static_cast(asn1_cause.nas().value); break; case asn1::ngap::cause_c::types_opts::protocol: - cause = static_cast(ngap_cause.protocol().value); + cause = static_cast(asn1_cause.protocol().value); break; case asn1::ngap::cause_c::types_opts::misc: - cause = static_cast(ngap_cause.misc().value); + cause = static_cast(asn1_cause.misc().value); break; default: - report_fatal_error("Cannot convert NGAP ASN.1 cause {} to common type", ngap_cause.type()); + report_fatal_error("Cannot convert NGAP ASN.1 cause {} to common type", asn1_cause.type()); } return cause; @@ -277,7 +174,7 @@ inline asn1::ngap::qos_flow_with_cause_item_s cu_cp_qos_flow_failed_to_setup_ite { asn1::ngap::qos_flow_with_cause_item_s asn1_failed_item; asn1_failed_item.qos_flow_id = qos_flow_id_to_uint(cu_cp_failed_item.qos_flow_id); - asn1_failed_item.cause = cause_to_ngap_asn1(cu_cp_failed_item.cause); + asn1_failed_item.cause = cause_to_asn1(cu_cp_failed_item.cause); return asn1_failed_item; } @@ -444,7 +341,7 @@ inline bool pdu_session_res_failed_to_modify_item_to_asn1(template_asn1_item& as asn1_resp.pdu_session_id = pdu_session_id_to_uint(resp.pdu_session_id); asn1::ngap::pdu_session_res_modify_unsuccessful_transfer_s response_transfer; - response_transfer.cause = cause_to_ngap_asn1(resp.unsuccessful_transfer.cause); + response_transfer.cause = cause_to_asn1(resp.unsuccessful_transfer.cause); // Pack transfer byte_buffer pdu = pack_into_pdu(response_transfer); @@ -468,7 +365,7 @@ inline bool pdu_session_res_setup_failed_item_to_asn1(template_asn1_item& asn1_resp.pdu_session_id = pdu_session_id_to_uint(resp.pdu_session_id); asn1::ngap::pdu_session_res_setup_unsuccessful_transfer_s setup_unsuccessful_transfer; - setup_unsuccessful_transfer.cause = cause_to_ngap_asn1(resp.unsuccessful_transfer.cause); + setup_unsuccessful_transfer.cause = cause_to_asn1(resp.unsuccessful_transfer.cause); // TODO: Add crit diagnostics @@ -901,7 +798,7 @@ inline bool pdu_session_res_failed_to_setup_item_ho_ack_to_asn1( asn1::ngap::ho_res_alloc_unsuccessful_transfer_s asn1_ho_res_alloc_unsuccessful_transfer; // cause - asn1_ho_res_alloc_unsuccessful_transfer.cause = cause_to_ngap_asn1(failed_item.unsuccessful_transfer.cause); + asn1_ho_res_alloc_unsuccessful_transfer.cause = cause_to_asn1(failed_item.unsuccessful_transfer.cause); // crit diagnostics if (failed_item.unsuccessful_transfer.crit_diagnostics.has_value()) { diff --git a/lib/ngap/ngap_asn1_helpers.h b/lib/ngap/ngap_asn1_helpers.h index 6136826050..9ff673253c 100644 --- a/lib/ngap/ngap_asn1_helpers.h +++ b/lib/ngap/ngap_asn1_helpers.h @@ -492,7 +492,7 @@ inline void fill_asn1_initial_context_setup_failure(asn1::ngap::init_context_set const ngap_init_context_setup_failure& fail) { // Fill cause - asn1_fail->cause = cause_to_ngap_asn1(fail.cause); + asn1_fail->cause = cause_to_asn1(fail.cause); // Fill PDU Session Resource Failed to Setup List if (!fail.pdu_session_res_failed_to_setup_items.empty()) { @@ -702,7 +702,7 @@ inline void fill_asn1_ue_context_release_request(asn1::ngap::ue_context_release_ } } - asn1_msg->cause = cause_to_ngap_asn1(msg.cause); + asn1_msg->cause = cause_to_asn1(msg.cause); } /// \brief Convert NGAP ASN1 PDU Session Resource Release Command ASN1 struct to common type. @@ -1167,7 +1167,7 @@ fill_asn1_handover_resource_allocation_response(asn1::ngap::ho_fail_s& { if (!ho_response.success) { // cause - asn1_ho_failure->cause = cause_to_ngap_asn1(ho_response.cause); + asn1_ho_failure->cause = cause_to_asn1(ho_response.cause); // crit diagnostics if (ho_response.crit_diagnostics.has_value()) { diff --git a/lib/ngap/ngap_error_indication_helper.h b/lib/ngap/ngap_error_indication_helper.h index 5dab2bdc6c..3d18c6fbd7 100644 --- a/lib/ngap/ngap_error_indication_helper.h +++ b/lib/ngap/ngap_error_indication_helper.h @@ -30,7 +30,7 @@ inline void send_error_indication(ngap_message_notifier& ngap_notifier, srslog::basic_logger& logger, optional ran_ue_id = {}, optional amf_ue_id = {}, - optional cause = {}) + optional cause = {}) { ngap_message ngap_msg = {}; ngap_msg.pdu.set_init_msg(); @@ -51,7 +51,7 @@ inline void send_error_indication(ngap_message_notifier& ngap_notifier, if (cause.has_value()) { error_ind->cause_present = true; - error_ind->cause = cause_to_ngap_asn1(cause.value()); + error_ind->cause = cause_to_asn1(cause.value()); } // TODO: Add missing values diff --git a/lib/ngap/ngap_impl.cpp b/lib/ngap/ngap_impl.cpp index 5c2c96be40..d3c80e554d 100644 --- a/lib/ngap/ngap_impl.cpp +++ b/lib/ngap/ngap_impl.cpp @@ -23,7 +23,7 @@ #include "procedures/ngap_ue_context_release_procedure.h" #include "srsran/asn1/ngap/common.h" #include "srsran/ngap/ngap_types.h" -#include "srsran/ran/cause.h" +#include "srsran/ran/cause/ngap_cause.h" #include "srsran/support/srsran_assert.h" using namespace srsran; @@ -255,7 +255,7 @@ void ngap_impl::handle_dl_nas_transport_message(const asn1::ngap::dl_nas_transpo logger.warning("ran_ue_id={} amf_ue_id={}: Dropping DlNasTransportMessage. UE context does not exist", msg->ran_ue_ngap_id, msg->amf_ue_ngap_id); - send_error_indication(ngap_notifier, logger, {}, {}, cause_radio_network_t::unknown_local_ue_ngap_id); + send_error_indication(ngap_notifier, logger, {}, {}, ngap_cause_radio_network_t::unknown_local_ue_ngap_id); return; } @@ -263,7 +263,7 @@ void ngap_impl::handle_dl_nas_transport_message(const asn1::ngap::dl_nas_transpo if (ue_ctxt.release_scheduled) { ue_ctxt.logger.log_info("Dropping DlNasTransportMessage. UE is already scheduled for release"); - schedule_error_indication(ue_ctxt.ue_ids.ue_index, cause_radio_network_t::unknown_local_ue_ngap_id); + schedule_error_indication(ue_ctxt.ue_ids.ue_index, ngap_cause_radio_network_t::unknown_local_ue_ngap_id); return; } @@ -294,7 +294,7 @@ void ngap_impl::handle_initial_context_setup_request(const asn1::ngap::init_cont logger.warning("ran_ue_id={} amf_ue_id={}: Dropping InitialContextSetupRequest. UE context does not exist", request->ran_ue_ngap_id, request->amf_ue_ngap_id); - send_error_indication(ngap_notifier, logger, {}, {}, cause_radio_network_t::unknown_local_ue_ngap_id); + send_error_indication(ngap_notifier, logger, {}, {}, ngap_cause_radio_network_t::unknown_local_ue_ngap_id); return; } @@ -302,7 +302,7 @@ void ngap_impl::handle_initial_context_setup_request(const asn1::ngap::init_cont if (ue_ctxt.release_scheduled) { ue_ctxt.logger.log_info("Dropping InitialContextSetup. UE is already scheduled for release"); - schedule_error_indication(ue_ctxt.ue_ids.ue_index, cause_radio_network_t::unknown_local_ue_ngap_id); + schedule_error_indication(ue_ctxt.ue_ids.ue_index, ngap_cause_radio_network_t::unknown_local_ue_ngap_id); return; } @@ -365,7 +365,7 @@ void ngap_impl::handle_pdu_session_resource_setup_request(const asn1::ngap::pdu_ logger.warning("ran_ue_id={} amf_ue_id={}: Dropping PduSessionResourceSetupRequest. UE context does not exist", request->ran_ue_ngap_id, request->amf_ue_ngap_id); - send_error_indication(ngap_notifier, logger, {}, {}, cause_radio_network_t::unknown_local_ue_ngap_id); + send_error_indication(ngap_notifier, logger, {}, {}, ngap_cause_radio_network_t::unknown_local_ue_ngap_id); return; } @@ -373,7 +373,7 @@ void ngap_impl::handle_pdu_session_resource_setup_request(const asn1::ngap::pdu_ if (ue_ctxt.release_scheduled) { ue_ctxt.logger.log_info("Dropping PduSessionResourceSetupRequest. UE is already scheduled for release"); - schedule_error_indication(ue_ctxt.ue_ids.ue_index, cause_radio_network_t::unknown_local_ue_ngap_id); + schedule_error_indication(ue_ctxt.ue_ids.ue_index, ngap_cause_radio_network_t::unknown_local_ue_ngap_id); return; } @@ -430,14 +430,14 @@ void ngap_impl::handle_pdu_session_resource_modify_request(const asn1::ngap::pdu logger.warning("ran_ue_id={} amf_ue_id={}: Dropping PduSessionResourceModifyRequest. UE context does not exist", request->ran_ue_ngap_id, request->amf_ue_ngap_id); - send_error_indication(ngap_notifier, logger, {}, {}, cause_radio_network_t::unknown_local_ue_ngap_id); + send_error_indication(ngap_notifier, logger, {}, {}, ngap_cause_radio_network_t::unknown_local_ue_ngap_id); return; } ngap_ue_context& ue_ctxt = ue_ctxt_list[uint_to_ran_ue_id(request->ran_ue_ngap_id)]; if (ue_ctxt.release_scheduled) { ue_ctxt.logger.log_info("Dropping PduSessionResourceModifyRequest. UE is already scheduled for release"); - schedule_error_indication(ue_ctxt.ue_ids.ue_index, cause_radio_network_t::unknown_local_ue_ngap_id); + schedule_error_indication(ue_ctxt.ue_ids.ue_index, ngap_cause_radio_network_t::unknown_local_ue_ngap_id); return; } @@ -445,7 +445,7 @@ void ngap_impl::handle_pdu_session_resource_modify_request(const asn1::ngap::pdu byte_buffer asn1_request_pdu = pack_into_pdu(request); if (asn1_request_pdu == ue_ctxt.last_pdu_session_resource_modify_request) { ue_ctxt.logger.log_warning("Received duplicate PduSessionResourceModifyRequest"); - schedule_error_indication(ue_ctxt.ue_ids.ue_index, cause_radio_network_t::unspecified); + schedule_error_indication(ue_ctxt.ue_ids.ue_index, ngap_cause_radio_network_t::unspecified); return; } @@ -470,7 +470,7 @@ void ngap_impl::handle_pdu_session_resource_modify_request(const asn1::ngap::pdu msg.ue_index = ue_ctxt.ue_ids.ue_index; if (!fill_cu_cp_pdu_session_resource_modify_request(msg, request->pdu_session_res_modify_list_mod_req)) { ue_ctxt.logger.log_warning("Unable to fill ASN1 contents for PduSessionResourceModifyRequest"); - schedule_error_indication(ue_ctxt.ue_ids.ue_index, cause_radio_network_t::unspecified); + schedule_error_indication(ue_ctxt.ue_ids.ue_index, ngap_cause_radio_network_t::unspecified); return; } @@ -492,7 +492,7 @@ void ngap_impl::handle_pdu_session_resource_release_command(const asn1::ngap::pd logger.warning("ran_ue_id={} amf_ue_id={}: Dropping PduSessionResourceReleaseCommand. UE context does not exist", command->ran_ue_ngap_id, command->amf_ue_ngap_id); - send_error_indication(ngap_notifier, logger, {}, {}, cause_radio_network_t::unknown_local_ue_ngap_id); + send_error_indication(ngap_notifier, logger, {}, {}, ngap_cause_radio_network_t::unknown_local_ue_ngap_id); return; } @@ -500,7 +500,7 @@ void ngap_impl::handle_pdu_session_resource_release_command(const asn1::ngap::pd if (ue_ctxt.release_scheduled) { ue_ctxt.logger.log_info("Dropping PduSessionResourceReleaseCommand. UE is already scheduled for release"); - schedule_error_indication(ue_ctxt.ue_ids.ue_index, cause_radio_network_t::unknown_local_ue_ngap_id); + schedule_error_indication(ue_ctxt.ue_ids.ue_index, ngap_cause_radio_network_t::unknown_local_ue_ngap_id); return; } @@ -518,7 +518,7 @@ void ngap_impl::handle_pdu_session_resource_release_command(const asn1::ngap::pd byte_buffer nas_pdu; if (!nas_pdu.resize(command->nas_pdu.size())) { ue_ctxt.logger.log_warning("Unable to resize the storage for the PduSessionResourceReleaseCommand PDU"); - schedule_error_indication(ue_ctxt.ue_ids.ue_index, cause_radio_network_t::unspecified); + schedule_error_indication(ue_ctxt.ue_ids.ue_index, ngap_cause_radio_network_t::unspecified); return; } std::copy(command->nas_pdu.begin(), command->nas_pdu.end(), nas_pdu.begin()); @@ -556,7 +556,7 @@ void ngap_impl::handle_ue_context_release_command(const asn1::ngap::ue_context_r logger.warning("{}amf_ue_id={}: Dropping UeContextReleaseCommand. UE does not exist", ran_ue_id == ran_ue_id_t::invalid ? "" : fmt::format("ran_ue_id={} ", ran_ue_id), amf_ue_id); - send_error_indication(ngap_notifier, logger, {}, amf_ue_id, cause_radio_network_t::unknown_local_ue_ngap_id); + send_error_indication(ngap_notifier, logger, {}, amf_ue_id, ngap_cause_radio_network_t::unknown_local_ue_ngap_id); return; } @@ -564,7 +564,7 @@ void ngap_impl::handle_ue_context_release_command(const asn1::ngap::ue_context_r if (ue_ctxt.release_scheduled) { ue_ctxt.logger.log_info("Dropping UeContextReleaseCommand. UE is already scheduled for release"); - schedule_error_indication(ue_ctxt.ue_ids.ue_index, cause_radio_network_t::unknown_local_ue_ngap_id, amf_ue_id); + schedule_error_indication(ue_ctxt.ue_ids.ue_index, ngap_cause_radio_network_t::unknown_local_ue_ngap_id, amf_ue_id); return; } @@ -684,7 +684,7 @@ void ngap_impl::handle_error_indication(const asn1::ngap::error_ind_s& msg) amf_ue_id = uint_to_amf_ue_id(msg->amf_ue_ngap_id); if (!ue_ctxt_list.contains(uint_to_amf_ue_id(msg->amf_ue_ngap_id))) { logger.warning("amf_ue_id={}: Dropping ErrorIndication. UE context does not exist", msg->amf_ue_ngap_id); - send_error_indication(ngap_notifier, logger, {}, {}, cause_radio_network_t::inconsistent_remote_ue_ngap_id); + send_error_indication(ngap_notifier, logger, {}, {}, ngap_cause_radio_network_t::inconsistent_remote_ue_ngap_id); return; } ue_index = ue_ctxt_list[amf_ue_id].ue_ids.ue_index; @@ -692,7 +692,7 @@ void ngap_impl::handle_error_indication(const asn1::ngap::error_ind_s& msg) ran_ue_id = uint_to_ran_ue_id(msg->ran_ue_ngap_id); if (!ue_ctxt_list.contains(uint_to_ran_ue_id(msg->ran_ue_ngap_id))) { logger.warning("ran_ue_id={}: Dropping ErrorIndication. UE context does not exist", msg->ran_ue_ngap_id); - send_error_indication(ngap_notifier, logger, {}, {}, cause_radio_network_t::unknown_local_ue_ngap_id); + send_error_indication(ngap_notifier, logger, {}, {}, ngap_cause_radio_network_t::unknown_local_ue_ngap_id); return; } ue_index = ue_ctxt_list[ran_ue_id].ue_ids.ue_index; @@ -706,8 +706,8 @@ void ngap_impl::handle_error_indication(const asn1::ngap::error_ind_s& msg) // Request UE release task_sched.schedule_async_task(ue_index, launch_async([this, ue_index](coro_context>& ctx) { CORO_BEGIN(ctx); - CORO_AWAIT(handle_ue_context_release_request( - cu_cp_ue_context_release_request{ue_index, {}, cause_nas_t::unspecified})); + CORO_AWAIT(handle_ue_context_release_request(cu_cp_ue_context_release_request{ + ue_index, {}, ngap_cause_radio_network_t::unspecified})); CORO_RETURN(); })); @@ -873,7 +873,7 @@ void ngap_impl::remove_ue_context(ue_index_t ue_index) ue_ctxt_list.remove_ue_context(ue_index); } -void ngap_impl::schedule_error_indication(ue_index_t ue_index, cause_t cause, optional amf_ue_id) +void ngap_impl::schedule_error_indication(ue_index_t ue_index, ngap_cause_t cause, optional amf_ue_id) { logger.info("{}{}: Scheduling ErrorIndication", ue_index != ue_index_t::invalid ? fmt::format("ue={}", ue_index) : "", @@ -907,7 +907,7 @@ void ngap_impl::on_pdu_session_setup_timer_expired(ue_index_t ue_index) CORO_BEGIN(ctx); CORO_AWAIT( ue->get_du_processor_control_notifier().on_new_ue_context_release_command( - {ue_index, cause_nas_t::unspecified})); + {ue_index, ngap_cause_radio_network_t::unspecified})); CORO_RETURN(); })); } else { @@ -917,8 +917,8 @@ void ngap_impl::on_pdu_session_setup_timer_expired(ue_index_t ue_index) // Request UE release task_sched.schedule_async_task(ue_index, launch_async([this, ue_index](coro_context>& ctx) { CORO_BEGIN(ctx); - CORO_AWAIT(handle_ue_context_release_request( - cu_cp_ue_context_release_request{ue_index, {}, cause_nas_t::unspecified})); + CORO_AWAIT(handle_ue_context_release_request(cu_cp_ue_context_release_request{ + ue_index, {}, ngap_cause_radio_network_t::unspecified})); CORO_RETURN(); })); } diff --git a/lib/ngap/ngap_impl.h b/lib/ngap/ngap_impl.h index f8e83b1a1c..3c002f19ef 100644 --- a/lib/ngap/ngap_impl.h +++ b/lib/ngap/ngap_impl.h @@ -125,7 +125,7 @@ class ngap_impl final : public ngap_interface /// \param[in] ue_index The index of the related UE. /// \param[in] cause The cause of the Error Indication. /// \param[in] amf_ue_id The AMF UE ID. - void schedule_error_indication(ue_index_t ue_index, cause_t cause, optional amf_ue_id = {}); + void schedule_error_indication(ue_index_t ue_index, ngap_cause_t cause, optional amf_ue_id = {}); /// \brief Callback for the PDU Session Setup Timer expiration. Triggers the release of the UE. void on_pdu_session_setup_timer_expired(ue_index_t ue_index); diff --git a/lib/ngap/ngap_validators/ngap_validators.cpp b/lib/ngap/ngap_validators/ngap_validators.cpp index 58530c7366..615a4a7a4a 100644 --- a/lib/ngap/ngap_validators/ngap_validators.cpp +++ b/lib/ngap/ngap_validators/ngap_validators.cpp @@ -33,7 +33,7 @@ pdu_session_resource_setup_validation_outcome srsran::srs_cu_cp::verify_pdu_sess // Add failed psi to response cu_cp_pdu_session_res_setup_failed_item failed_item; failed_item.pdu_session_id = psi; - failed_item.unsuccessful_transfer.cause = cause_radio_network_t::multiple_pdu_session_id_instances; + failed_item.unsuccessful_transfer.cause = ngap_cause_radio_network_t::multiple_pdu_session_id_instances; verification_outcome.response.pdu_session_res_failed_to_setup_items.emplace(psi, failed_item); } } @@ -60,7 +60,7 @@ pdu_session_resource_setup_validation_outcome srsran::srs_cu_cp::verify_pdu_sess // Add failed psi to response cu_cp_pdu_session_res_setup_failed_item failed_item; failed_item.pdu_session_id = psi; - failed_item.unsuccessful_transfer.cause = cause_radio_network_t::invalid_qos_combination; + failed_item.unsuccessful_transfer.cause = ngap_cause_radio_network_t::invalid_qos_combination; verification_outcome.response.pdu_session_res_failed_to_setup_items.emplace(psi, failed_item); // If single QoS flow fails, then the whole PDU session fails break; @@ -104,7 +104,7 @@ pdu_session_resource_modify_validation_outcome srsran::srs_cu_cp::verify_pdu_ses // Add failed psi to response cu_cp_pdu_session_res_setup_failed_item failed_item; failed_item.pdu_session_id = psi; - failed_item.unsuccessful_transfer.cause = cause_radio_network_t::multiple_pdu_session_id_instances; + failed_item.unsuccessful_transfer.cause = ngap_cause_radio_network_t::multiple_pdu_session_id_instances; verification_outcome.response.pdu_session_res_failed_to_modify_list.emplace(psi, failed_item); } } diff --git a/lib/ngap/procedures/ngap_initial_context_setup_procedure.cpp b/lib/ngap/procedures/ngap_initial_context_setup_procedure.cpp index d8358bcd57..7bdedb6e32 100644 --- a/lib/ngap/procedures/ngap_initial_context_setup_procedure.cpp +++ b/lib/ngap/procedures/ngap_initial_context_setup_procedure.cpp @@ -14,7 +14,7 @@ #include "srsran/asn1/ngap/common.h" #include "srsran/ngap/ngap.h" #include "srsran/ngap/ngap_message.h" -#include "srsran/ran/cause.h" +#include "srsran/ran/cause/ngap_cause.h" using namespace srsran; using namespace srsran::srs_cu_cp; @@ -56,7 +56,7 @@ void ngap_initial_context_setup_procedure::operator()(coro_context(e1ap_cause)) { + ngap_cause = ngap_cause_radio_network_t( + e1ap_to_ngap_cause_radio_network[uint8_t(variant_get(e1ap_cause))]); + } else if (variant_holds_alternative(e1ap_cause)) { + ngap_cause = + ngap_cause_transport_t(e1ap_to_ngap_cause_transport[uint8_t(variant_get(e1ap_cause))]); + } else if (variant_holds_alternative(e1ap_cause)) { + ngap_cause = variant_get(e1ap_cause); + } else if (variant_holds_alternative(e1ap_cause)) { + ngap_cause = ngap_cause_misc_t(e1ap_to_ngap_cause_misc[uint8_t(variant_get(e1ap_cause))]); + } else { + report_fatal_error("Cannot convert cause to NGAP type: {}", e1ap_cause); + } + + return ngap_cause; +}; diff --git a/lib/ran/cause/f1ap_cause_converters.cpp b/lib/ran/cause/f1ap_cause_converters.cpp new file mode 100644 index 0000000000..6f88b56289 --- /dev/null +++ b/lib/ran/cause/f1ap_cause_converters.cpp @@ -0,0 +1,94 @@ +/* + * + * 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/ran/cause/f1ap_cause_converters.h" +#include "srsran/support/error_handling.h" + +using namespace srsran; + +const uint8_t f1ap_to_ngap_cause_radio_network[] = { + (uint8_t)ngap_cause_radio_network_t::unspecified, // unspecified + (uint8_t)ngap_cause_radio_network_t::radio_conn_with_ue_lost, // rl_fail_rlc + (uint8_t)ngap_cause_radio_network_t::unspecified, // unknown_or_already_allocated_gnb_cu_ue_f1ap_id + (uint8_t)ngap_cause_radio_network_t::unspecified, // unknown_or_already_allocated_gnb_du_ue_f1ap_id + (uint8_t)ngap_cause_radio_network_t::unspecified, // unknown_or_inconsistent_pair_of_ue_f1ap_id + (uint8_t)ngap_cause_radio_network_t::interaction_with_other_proc, // interaction_with_other_proc + (uint8_t)ngap_cause_radio_network_t::unspecified, // not_supported_qci_value + (uint8_t)ngap_cause_radio_network_t::unspecified, // action_desirable_for_radio_reasons + (uint8_t)ngap_cause_radio_network_t::no_radio_res_available_in_target_cell, // no_radio_res_available + (uint8_t)ngap_cause_radio_network_t::unspecified, // proc_cancelled + (uint8_t)ngap_cause_radio_network_t::unspecified, // normal_release + (uint8_t)ngap_cause_radio_network_t::cell_not_available, // cell_not_available + (uint8_t)ngap_cause_radio_network_t::radio_conn_with_ue_lost, // rl_fail_others + (uint8_t)ngap_cause_radio_network_t::unspecified, // ue_rejection + (uint8_t)ngap_cause_radio_network_t::res_not_available_for_the_slice, // res_not_available_for_the_slice + (uint8_t)ngap_cause_radio_network_t::unspecified, // amf_initiated_abnormal_release + (uint8_t)ngap_cause_radio_network_t::unspecified, // release_due_to_pre_emption + (uint8_t)ngap_cause_radio_network_t::unspecified, // plmn_not_served_by_the_gnb_cu + (uint8_t)ngap_cause_radio_network_t::unspecified, // multiple_drb_id_instances + (uint8_t)ngap_cause_radio_network_t::unspecified, // unknown_drb_id + (uint8_t)ngap_cause_radio_network_t::unspecified, // multiple_bh_rlc_ch_id_instances + (uint8_t)ngap_cause_radio_network_t::unspecified, // unknown_bh_rlc_ch_id + (uint8_t)ngap_cause_radio_network_t::unspecified, // cho_cpc_res_tobechanged + (uint8_t)ngap_cause_radio_network_t::unspecified, // npn_not_supported + (uint8_t)ngap_cause_radio_network_t::unspecified, // npn_access_denied + (uint8_t)ngap_cause_radio_network_t::unspecified, // gnb_cu_cell_capacity_exceeded + (uint8_t)ngap_cause_radio_network_t::unspecified, // report_characteristics_empty + (uint8_t)ngap_cause_radio_network_t::unspecified, // existing_meas_id + (uint8_t)ngap_cause_radio_network_t::unspecified, // meas_temporarily_not_available + (uint8_t)ngap_cause_radio_network_t::unspecified, // meas_not_supported_for_the_obj + (uint8_t)ngap_cause_radio_network_t::unspecified, // unknown_bh_address + (uint8_t)ngap_cause_radio_network_t::unspecified, // unknown_bap_routing_id + (uint8_t)ngap_cause_radio_network_t::unspecified, // insufficient_ue_cap + (uint8_t)ngap_cause_radio_network_t::unspecified, // scg_activation_deactivation_fail + (uint8_t)ngap_cause_radio_network_t::unspecified, // scg_deactivation_fail_due_to_data_tx + (uint8_t)ngap_cause_radio_network_t::unspecified, // requested_item_not_supported_on_time + (uint8_t)ngap_cause_radio_network_t::unspecified, // unknown_or_already_allocated_gnb_cu_mbs_f1ap_id + (uint8_t)ngap_cause_radio_network_t::unspecified, // unknown_or_already_allocated_gnb_du_mbs_f1ap_id + (uint8_t)ngap_cause_radio_network_t::unspecified, // unknown_or_inconsistent_pair_of_mbs_f1ap_id + (uint8_t)ngap_cause_radio_network_t::unspecified, // unknown_or_inconsistent_mrb_id + (uint8_t)ngap_cause_radio_network_t::unspecified // tat_sdt_expiry +}; + +const uint8_t f1ap_to_ngap_cause_transport[] = { + (uint8_t)ngap_cause_transport_t::transport_res_unavailable, // transport_res_unavailable + (uint8_t)ngap_cause_transport_t::unspecified, // unspecified + (uint8_t)ngap_cause_transport_t::unspecified, // unknown_tnl_address_for_iab + (uint8_t)ngap_cause_transport_t::unspecified, // unknown_up_tnl_info_for_iab +}; + +const uint8_t f1ap_to_ngap_cause_misc[] = { + (uint8_t)ngap_cause_misc_t::ctrl_processing_overload, // ctrl_processing_overload + (uint8_t)ngap_cause_misc_t::not_enough_user_plane_processing_res, // not_enough_user_plane_processing_res + (uint8_t)ngap_cause_misc_t::hardware_fail, // hardware_fail + (uint8_t)ngap_cause_misc_t::om_intervention, // om_intervention + (uint8_t)ngap_cause_misc_t::unspecified // unspecified +}; + +ngap_cause_t srsran::f1ap_to_ngap_cause(f1ap_cause_t f1ap_cause) +{ + ngap_cause_t ngap_cause; + + if (variant_holds_alternative(f1ap_cause)) { + ngap_cause = ngap_cause_radio_network_t( + f1ap_to_ngap_cause_radio_network[uint8_t(variant_get(f1ap_cause))]); + } else if (variant_holds_alternative(f1ap_cause)) { + ngap_cause = + ngap_cause_transport_t(f1ap_to_ngap_cause_transport[uint8_t(variant_get(f1ap_cause))]); + } else if (variant_holds_alternative(f1ap_cause)) { + ngap_cause = variant_get(f1ap_cause); + } else if (variant_holds_alternative(f1ap_cause)) { + ngap_cause = ngap_cause_misc_t(f1ap_to_ngap_cause_misc[uint8_t(variant_get(f1ap_cause))]); + } else { + report_fatal_error("Cannot convert cause to F1AP type: {}", f1ap_cause); + } + + return ngap_cause; +}; diff --git a/lib/ran/cause/ngap_cause_converters.cpp b/lib/ran/cause/ngap_cause_converters.cpp new file mode 100644 index 0000000000..44954807fa --- /dev/null +++ b/lib/ran/cause/ngap_cause_converters.cpp @@ -0,0 +1,238 @@ +/* + * + * 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/ran/cause/ngap_cause_converters.h" +#include "srsran/support/error_handling.h" + +using namespace srsran; + +const uint8_t ngap_to_f1ap_cause_radio_network[] = { + (uint8_t)f1ap_cause_radio_network_t::unspecified, // unspecified + (uint8_t)f1ap_cause_radio_network_t::unspecified, // txnrelocoverall_expiry + (uint8_t)f1ap_cause_radio_network_t::unspecified, // successful_ho + (uint8_t)f1ap_cause_radio_network_t::unspecified, // release_due_to_ngran_generated_reason + (uint8_t)f1ap_cause_radio_network_t::unspecified, // release_due_to_5gc_generated_reason + (uint8_t)f1ap_cause_radio_network_t::unspecified, // ho_cancelled + (uint8_t)f1ap_cause_radio_network_t::unspecified, // partial_ho + (uint8_t)f1ap_cause_radio_network_t::unspecified, // ho_fail_in_target_5_gc_ngran_node_or_target_sys + (uint8_t)f1ap_cause_radio_network_t::unspecified, // ho_target_not_allowed + (uint8_t)f1ap_cause_radio_network_t::unspecified, // tngrelocoverall_expiry + (uint8_t)f1ap_cause_radio_network_t::unspecified, // tngrelocprep_expiry + (uint8_t)f1ap_cause_radio_network_t::unspecified, // cell_not_available + (uint8_t)f1ap_cause_radio_network_t::unspecified, // unknown_target_id + (uint8_t)f1ap_cause_radio_network_t::unspecified, // no_radio_res_available_in_target_cell + (uint8_t)f1ap_cause_radio_network_t::unspecified, // unknown_local_ue_ngap_id + (uint8_t)f1ap_cause_radio_network_t::unspecified, // inconsistent_remote_ue_ngap_id + (uint8_t)f1ap_cause_radio_network_t::unspecified, // ho_desirable_for_radio_reason + (uint8_t)f1ap_cause_radio_network_t::unspecified, // time_crit_ho + (uint8_t)f1ap_cause_radio_network_t::unspecified, // res_optim_ho + (uint8_t)f1ap_cause_radio_network_t::unspecified, // reduce_load_in_serving_cell + (uint8_t)f1ap_cause_radio_network_t::unspecified, // user_inactivity + (uint8_t)f1ap_cause_radio_network_t::unspecified, // radio_conn_with_ue_lost + (uint8_t)f1ap_cause_radio_network_t::unspecified, // radio_res_not_available + (uint8_t)f1ap_cause_radio_network_t::unspecified, // invalid_qos_combination + (uint8_t)f1ap_cause_radio_network_t::unspecified, // fail_in_radio_interface_proc + (uint8_t)f1ap_cause_radio_network_t::unspecified, // interaction_with_other_proc + (uint8_t)f1ap_cause_radio_network_t::unspecified, // unknown_pdu_session_id + (uint8_t)f1ap_cause_radio_network_t::unspecified, // unkown_qos_flow_id + (uint8_t)f1ap_cause_radio_network_t::unspecified, // multiple_pdu_session_id_instances + (uint8_t)f1ap_cause_radio_network_t::unspecified, // multiple_qos_flow_id_instances + (uint8_t)f1ap_cause_radio_network_t::unspecified, // encryption_and_or_integrity_protection_algorithms_not_supported + (uint8_t)f1ap_cause_radio_network_t::unspecified, // ng_intra_sys_ho_triggered + (uint8_t)f1ap_cause_radio_network_t::unspecified, // ng_inter_sys_ho_triggered + (uint8_t)f1ap_cause_radio_network_t::unspecified, // xn_ho_triggered + (uint8_t)f1ap_cause_radio_network_t::unspecified, // not_supported_5qi_value + (uint8_t)f1ap_cause_radio_network_t::unspecified, // ue_context_transfer + (uint8_t)f1ap_cause_radio_network_t::unspecified, // ims_voice_eps_fallback_or_rat_fallback_triggered + (uint8_t)f1ap_cause_radio_network_t::unspecified, // up_integrity_protection_not_possible + (uint8_t)f1ap_cause_radio_network_t::unspecified, // up_confidentiality_protection_not_possible + (uint8_t)f1ap_cause_radio_network_t::unspecified, // slice_not_supported + (uint8_t)f1ap_cause_radio_network_t::unspecified, // ue_in_rrc_inactive_state_not_reachable + (uint8_t)f1ap_cause_radio_network_t::unspecified, // redirection + (uint8_t)f1ap_cause_radio_network_t::unspecified, // res_not_available_for_the_slice + (uint8_t)f1ap_cause_radio_network_t::unspecified, // ue_max_integrity_protected_data_rate_reason + (uint8_t)f1ap_cause_radio_network_t::unspecified, // release_due_to_cn_detected_mob + (uint8_t)f1ap_cause_radio_network_t::unspecified, // n26_interface_not_available + (uint8_t)f1ap_cause_radio_network_t::unspecified, // release_due_to_pre_emption + (uint8_t)f1ap_cause_radio_network_t::unspecified, // multiple_location_report_ref_id_instances + (uint8_t)f1ap_cause_radio_network_t::unspecified, // rsn_not_available_for_the_up + (uint8_t)f1ap_cause_radio_network_t::unspecified, // npn_access_denied + (uint8_t)f1ap_cause_radio_network_t::unspecified, // cag_only_access_denied + (uint8_t)f1ap_cause_radio_network_t::unspecified, // insufficient_ue_cap + (uint8_t)f1ap_cause_radio_network_t::unspecified, // redcap_ue_not_supported + (uint8_t)f1ap_cause_radio_network_t::unspecified, // unknown_mbs_session_id + (uint8_t)f1ap_cause_radio_network_t::unspecified, // indicated_mbs_session_area_info_not_served_by_the_gnb + (uint8_t)f1ap_cause_radio_network_t::unspecified, // inconsistent_slice_info_for_the_session + (uint8_t)f1ap_cause_radio_network_t::unspecified // misaligned_assoc_for_multicast_unicast +}; + +const uint8_t ngap_to_f1ap_cause_transport[] = { + (uint8_t)f1ap_cause_transport_t::transport_res_unavailable, // transport_res_unavailable + (uint8_t)f1ap_cause_transport_t::unspecified // unspecified +}; + +const uint8_t ngap_to_f1ap_cause_misc[] = { + (uint8_t)cause_misc_t::unspecified, // ctrl_processing_overload + (uint8_t)cause_misc_t::unspecified, // not_enough_user_plane_processing_res + (uint8_t)cause_misc_t::unspecified, // hardware_fail + (uint8_t)cause_misc_t::unspecified, // om_intervention + (uint8_t)cause_misc_t::unspecified, // unknown_plmn_or_sn_pn + (uint8_t)cause_misc_t::unspecified, // unspecified +}; + +f1ap_cause_t srsran::ngap_to_f1ap_cause(ngap_cause_t ngap_cause) +{ + f1ap_cause_t f1ap_cause; + + if (variant_holds_alternative(ngap_cause)) { + f1ap_cause = f1ap_cause_radio_network_t( + ngap_to_f1ap_cause_radio_network[uint8_t(variant_get(ngap_cause))]); + } else if (variant_holds_alternative(ngap_cause)) { + f1ap_cause = + f1ap_cause_transport_t(ngap_to_f1ap_cause_transport[uint8_t(variant_get(ngap_cause))]); + } else if (variant_holds_alternative(ngap_cause)) { + switch (variant_get(ngap_cause)) { + case cause_nas_t::normal_release: + f1ap_cause = f1ap_cause_radio_network_t::normal_release; + break; + case cause_nas_t::authentication_fail: + f1ap_cause = f1ap_cause_radio_network_t::unspecified; + break; + case cause_nas_t::deregister: + f1ap_cause = f1ap_cause_radio_network_t::normal_release; + break; + case cause_nas_t::unspecified: + f1ap_cause = f1ap_cause_radio_network_t::unspecified; + break; + default: + report_fatal_error("Cannot convert cause to F1AP type: {}", ngap_cause); + } + } else if (variant_holds_alternative(ngap_cause)) { + f1ap_cause = variant_get(ngap_cause); + } else if (variant_holds_alternative(ngap_cause)) { + f1ap_cause = cause_misc_t(ngap_to_f1ap_cause_misc[uint8_t(variant_get(ngap_cause))]); + } else { + report_fatal_error("Cannot convert cause to F1AP type: {}", ngap_cause); + } + + return f1ap_cause; +}; + +const uint8_t ngap_to_e1ap_cause_radio_network[] = { + (uint8_t)e1ap_cause_radio_network_t::unspecified, // unspecified + (uint8_t)e1ap_cause_radio_network_t::unspecified, // txnrelocoverall_expiry + (uint8_t)e1ap_cause_radio_network_t::unspecified, // successful_ho + (uint8_t)e1ap_cause_radio_network_t::unspecified, // release_due_to_ngran_generated_reason + (uint8_t)e1ap_cause_radio_network_t::unspecified, // release_due_to_5gc_generated_reason + (uint8_t)e1ap_cause_radio_network_t::unspecified, // ho_cancelled + (uint8_t)e1ap_cause_radio_network_t::unspecified, // partial_ho + (uint8_t)e1ap_cause_radio_network_t::unspecified, // ho_fail_in_target_5_gc_ngran_node_or_target_sys + (uint8_t)e1ap_cause_radio_network_t::unspecified, // ho_target_not_allowed + (uint8_t)e1ap_cause_radio_network_t::unspecified, // tngrelocoverall_expiry + (uint8_t)e1ap_cause_radio_network_t::unspecified, // tngrelocprep_expiry + (uint8_t)e1ap_cause_radio_network_t::unspecified, // cell_not_available + (uint8_t)e1ap_cause_radio_network_t::unspecified, // unknown_target_id + (uint8_t)e1ap_cause_radio_network_t::unspecified, // no_radio_res_available_in_target_cell + (uint8_t)e1ap_cause_radio_network_t::unspecified, // unknown_local_ue_ngap_id + (uint8_t)e1ap_cause_radio_network_t::unspecified, // inconsistent_remote_ue_ngap_id + (uint8_t)e1ap_cause_radio_network_t::unspecified, // ho_desirable_for_radio_reason + (uint8_t)e1ap_cause_radio_network_t::unspecified, // time_crit_ho + (uint8_t)e1ap_cause_radio_network_t::unspecified, // res_optim_ho + (uint8_t)e1ap_cause_radio_network_t::unspecified, // reduce_load_in_serving_cell + (uint8_t)e1ap_cause_radio_network_t::unspecified, // user_inactivity + (uint8_t)e1ap_cause_radio_network_t::unspecified, // radio_conn_with_ue_lost + (uint8_t)e1ap_cause_radio_network_t::unspecified, // radio_res_not_available + (uint8_t)e1ap_cause_radio_network_t::unspecified, // invalid_qos_combination + (uint8_t)e1ap_cause_radio_network_t::unspecified, // fail_in_radio_interface_proc + (uint8_t)e1ap_cause_radio_network_t::unspecified, // interaction_with_other_proc + (uint8_t)e1ap_cause_radio_network_t::unspecified, // unknown_pdu_session_id + (uint8_t)e1ap_cause_radio_network_t::unspecified, // unkown_qos_flow_id + (uint8_t)e1ap_cause_radio_network_t::unspecified, // multiple_pdu_session_id_instances + (uint8_t)e1ap_cause_radio_network_t::unspecified, // multiple_qos_flow_id_instances + (uint8_t)e1ap_cause_radio_network_t::unspecified, // encryption_and_or_integrity_protection_algorithms_not_supported + (uint8_t)e1ap_cause_radio_network_t::unspecified, // ng_intra_sys_ho_triggered + (uint8_t)e1ap_cause_radio_network_t::unspecified, // ng_inter_sys_ho_triggered + (uint8_t)e1ap_cause_radio_network_t::unspecified, // xn_ho_triggered + (uint8_t)e1ap_cause_radio_network_t::unspecified, // not_supported_5qi_value + (uint8_t)e1ap_cause_radio_network_t::unspecified, // ue_context_transfer + (uint8_t)e1ap_cause_radio_network_t::unspecified, // ims_voice_eps_fallback_or_rat_fallback_triggered + (uint8_t)e1ap_cause_radio_network_t::unspecified, // up_integrity_protection_not_possible + (uint8_t)e1ap_cause_radio_network_t::unspecified, // up_confidentiality_protection_not_possible + (uint8_t)e1ap_cause_radio_network_t::unspecified, // slice_not_supported + (uint8_t)e1ap_cause_radio_network_t::unspecified, // ue_in_rrc_inactive_state_not_reachable + (uint8_t)e1ap_cause_radio_network_t::unspecified, // redirection + (uint8_t)e1ap_cause_radio_network_t::unspecified, // res_not_available_for_the_slice + (uint8_t)e1ap_cause_radio_network_t::unspecified, // ue_max_integrity_protected_data_rate_reason + (uint8_t)e1ap_cause_radio_network_t::unspecified, // release_due_to_cn_detected_mob + (uint8_t)e1ap_cause_radio_network_t::unspecified, // n26_interface_not_available + (uint8_t)e1ap_cause_radio_network_t::unspecified, // release_due_to_pre_emption + (uint8_t)e1ap_cause_radio_network_t::unspecified, // multiple_location_report_ref_id_instances + (uint8_t)e1ap_cause_radio_network_t::unspecified, // rsn_not_available_for_the_up + (uint8_t)e1ap_cause_radio_network_t::unspecified, // npn_access_denied + (uint8_t)e1ap_cause_radio_network_t::unspecified, // cag_only_access_denied + (uint8_t)e1ap_cause_radio_network_t::unspecified, // insufficient_ue_cap + (uint8_t)e1ap_cause_radio_network_t::unspecified, // redcap_ue_not_supported + (uint8_t)e1ap_cause_radio_network_t::unspecified, // unknown_mbs_session_id + (uint8_t)e1ap_cause_radio_network_t::unspecified, // indicated_mbs_session_area_info_not_served_by_the_gnb + (uint8_t)e1ap_cause_radio_network_t::unspecified, // inconsistent_slice_info_for_the_session + (uint8_t)e1ap_cause_radio_network_t::unspecified // misaligned_assoc_for_multicast_unicast +}; + +const uint8_t ngap_to_e1ap_cause_transport[] = { + (uint8_t)e1ap_cause_transport_t::transport_res_unavailable, // transport_res_unavailable + (uint8_t)e1ap_cause_transport_t::unspecified // unspecified +}; + +const uint8_t ngap_to_e1ap_cause_misc[] = { + (uint8_t)cause_misc_t::unspecified, // ctrl_processing_overload + (uint8_t)cause_misc_t::unspecified, // not_enough_user_plane_processing_res + (uint8_t)cause_misc_t::unspecified, // hardware_fail + (uint8_t)cause_misc_t::unspecified, // om_intervention + (uint8_t)cause_misc_t::unspecified, // unknown_plmn_or_sn_pn + (uint8_t)cause_misc_t::unspecified // unspecified +}; + +e1ap_cause_t srsran::ngap_to_e1ap_cause(ngap_cause_t ngap_cause) +{ + e1ap_cause_t e1ap_cause; + + if (variant_holds_alternative(ngap_cause)) { + e1ap_cause = e1ap_cause_radio_network_t( + ngap_to_e1ap_cause_radio_network[uint8_t(variant_get(ngap_cause))]); + } else if (variant_holds_alternative(ngap_cause)) { + e1ap_cause = + e1ap_cause_transport_t(ngap_to_e1ap_cause_transport[uint8_t(variant_get(ngap_cause))]); + } else if (variant_holds_alternative(ngap_cause)) { + switch (variant_get(ngap_cause)) { + case cause_nas_t::normal_release: + e1ap_cause = e1ap_cause_radio_network_t::normal_release; + break; + case cause_nas_t::authentication_fail: + e1ap_cause = e1ap_cause_radio_network_t::unspecified; + break; + case cause_nas_t::deregister: + e1ap_cause = e1ap_cause_radio_network_t::normal_release; + break; + case cause_nas_t::unspecified: + e1ap_cause = e1ap_cause_radio_network_t::unspecified; + break; + default: + report_fatal_error("Cannot convert cause to E1AP type: {}", ngap_cause); + } + } else if (variant_holds_alternative(ngap_cause)) { + e1ap_cause = variant_get(ngap_cause); + } else if (variant_holds_alternative(ngap_cause)) { + e1ap_cause = cause_misc_t(ngap_to_e1ap_cause_misc[uint8_t(variant_get(ngap_cause))]); + } else { + report_fatal_error("Cannot convert cause to E1AP type: {}", ngap_cause); + } + + return e1ap_cause; +}; diff --git a/lib/rrc/ue/procedures/rrc_reconfiguration_procedure.cpp b/lib/rrc/ue/procedures/rrc_reconfiguration_procedure.cpp index c6ec2c52d7..7165a2d274 100644 --- a/lib/rrc/ue/procedures/rrc_reconfiguration_procedure.cpp +++ b/lib/rrc/ue/procedures/rrc_reconfiguration_procedure.cpp @@ -10,7 +10,7 @@ #include "rrc_reconfiguration_procedure.h" #include "../rrc_asn1_helpers.h" -#include "srsran/ran/cause.h" +#include "srsran/ran/cause/ngap_cause.h" using namespace srsran; using namespace srsran::srs_cu_cp; @@ -69,11 +69,11 @@ void rrc_reconfiguration_procedure::operator()(coro_context>& c // Notify NGAP to request UE context release from AMF CORO_AWAIT_VALUE(release_request_sent, ngap_ctrl_notifier.on_ue_context_release_request( - {context.ue_index, {}, cause_radio_network_t::release_due_to_ngran_generated_reason})); + {context.ue_index, {}, ngap_cause_radio_network_t::release_due_to_ngran_generated_reason})); if (!release_request_sent) { // If NGAP release request was not sent to AMF, release UE from DU processor, RRC and F1AP - CORO_AWAIT( - du_processor_notifier.on_ue_context_release_command({context.ue_index, cause_radio_network_t::unspecified})); + CORO_AWAIT(du_processor_notifier.on_ue_context_release_command( + {context.ue_index, ngap_cause_radio_network_t::unspecified})); } } diff --git a/lib/rrc/ue/procedures/rrc_reestablishment_procedure.cpp b/lib/rrc/ue/procedures/rrc_reestablishment_procedure.cpp index f53564c226..527a22841e 100644 --- a/lib/rrc/ue/procedures/rrc_reestablishment_procedure.cpp +++ b/lib/rrc/ue/procedures/rrc_reestablishment_procedure.cpp @@ -102,7 +102,7 @@ void rrc_reestablishment_procedure::operator()(coro_context>& c "\"{}\" for old_ue={} failed. Requesting UE context release", name(), reestablishment_context.ue_index); // Release the old UE ue_context_release_request.ue_index = context.ue_index; - ue_context_release_request.cause = cause_radio_network_t::unspecified; + ue_context_release_request.cause = ngap_cause_radio_network_t::unspecified; CORO_AWAIT(ngap_ctrl_notifier.on_ue_context_release_request(ue_context_release_request)); } else { logger.log_debug("\"{}\" for old_ue={} finalized", name(), reestablishment_context.ue_index); @@ -145,7 +145,7 @@ async_task rrc_reestablishment_procedure::handle_rrc_reestablishment_fallb logger.log_debug("old_ue={} was not fully attached yet. Requesting UE context release", reestablishment_context.ue_index); ue_context_release_request.ue_index = reestablishment_context.ue_index; - ue_context_release_request.cause = cause_radio_network_t::unspecified; + ue_context_release_request.cause = ngap_cause_radio_network_t::unspecified; CORO_AWAIT(ngap_ctrl_notifier.on_ue_context_release_request(ue_context_release_request)); } diff --git a/lib/rrc/ue/rrc_ue_impl.cpp b/lib/rrc/ue/rrc_ue_impl.cpp index 8492151f7f..642a616105 100644 --- a/lib/rrc/ue/rrc_ue_impl.cpp +++ b/lib/rrc/ue/rrc_ue_impl.cpp @@ -159,7 +159,7 @@ byte_buffer rrc_ue_impl::get_packed_handover_preparation_message() return pack_into_pdu(ho_prep, "handover preparation info"); } -void rrc_ue_impl::on_ue_release_required(const cause_t& cause) +void rrc_ue_impl::on_ue_release_required(const ngap_cause_t& cause) { task_sched.schedule_async_task( launch_async([this, ngap_release_result = bool{false}, cause](coro_context>& ctx) mutable { diff --git a/lib/rrc/ue/rrc_ue_impl.h b/lib/rrc/ue/rrc_ue_impl.h index 159088df27..b26ba81125 100644 --- a/lib/rrc/ue/rrc_ue_impl.h +++ b/lib/rrc/ue/rrc_ue_impl.h @@ -97,7 +97,7 @@ class rrc_ue_impl final : public rrc_ue_interface // rrc_ue_setup_proc_notifier void on_new_dl_ccch(const asn1::rrc_nr::dl_ccch_msg_s& dl_ccch_msg) override; - void on_ue_release_required(const cause_t& cause) override; + void on_ue_release_required(const ngap_cause_t& cause) override; // rrc_ue_security_mode_command_proc_notifier void on_new_dl_dcch(srb_id_t srb_id, const asn1::rrc_nr::dl_dcch_msg_s& dl_ccch_msg) override; diff --git a/lib/rrc/ue/rrc_ue_message_handlers.cpp b/lib/rrc/ue/rrc_ue_message_handlers.cpp index ef6511cd4f..e9ab4310fe 100644 --- a/lib/rrc/ue/rrc_ue_message_handlers.cpp +++ b/lib/rrc/ue/rrc_ue_message_handlers.cpp @@ -33,7 +33,7 @@ void rrc_ue_impl::handle_ul_ccch_pdu(byte_buffer pdu) if (ul_ccch_msg.unpack(bref) != asn1::SRSASN_SUCCESS or ul_ccch_msg.msg.type().value != ul_ccch_msg_type_c::types_opts::c1) { logger.log_error(pdu.begin(), pdu.end(), "Failed to unpack CCCH UL PDU"); - on_ue_release_required(cause_radio_network_t::unspecified); + on_ue_release_required(ngap_cause_radio_network_t::unspecified); return; } } @@ -51,7 +51,7 @@ void rrc_ue_impl::handle_ul_ccch_pdu(byte_buffer pdu) break; default: logger.log_error("Unsupported CCCH UL message type"); - on_ue_release_required(cause_radio_network_t::unspecified); + on_ue_release_required(ngap_cause_radio_network_t::unspecified); } } @@ -60,7 +60,7 @@ void rrc_ue_impl::handle_rrc_setup_request(const asn1::rrc_nr::rrc_setup_request // Perform various checks to make sure we can serve the RRC Setup Request if (not cu_cp_notifier.on_ue_setup_request()) { logger.log_error("Sending Connection Reject. Cause: RRC connections not allowed"); - on_ue_release_required(cause_radio_network_t::unspecified); + on_ue_release_required(ngap_cause_radio_network_t::unspecified); return; } @@ -68,7 +68,7 @@ void rrc_ue_impl::handle_rrc_setup_request(const asn1::rrc_nr::rrc_setup_request // If the DU to CU container is missing, assume the DU can't serve the UE, so the CU-CP should reject the UE, see // TS 38.473 section 8.4.1.2. logger.log_debug("Sending rrcReject. Cause: DU is not able to serve the UE"); - on_ue_release_required(cause_radio_network_t::unspecified); + on_ue_release_required(ngap_cause_radio_network_t::unspecified); return; } @@ -91,7 +91,7 @@ void rrc_ue_impl::handle_rrc_setup_request(const asn1::rrc_nr::rrc_setup_request break; default: logger.log_error("Unsupported RrcSetupRequest"); - on_ue_release_required(cause_radio_network_t::unspecified); + on_ue_release_required(ngap_cause_radio_network_t::unspecified); return; } context.connection_cause.value = request_ies.establishment_cause.value; diff --git a/tests/unittests/asn1/CMakeLists.txt b/tests/unittests/asn1/CMakeLists.txt index 9e507c54ac..5e166d41d2 100644 --- a/tests/unittests/asn1/CMakeLists.txt +++ b/tests/unittests/asn1/CMakeLists.txt @@ -38,5 +38,5 @@ target_link_libraries(asn1_ngap_test ngap_asn1 srslog srsran_support srsran_pcap gtest_discover_tests(asn1_ngap_test) add_executable(asn1_cause_conversion_test asn1_cause_conversion_test.cpp) -target_link_libraries(asn1_cause_conversion_test ngap_asn1 f1ap_asn1 e1ap_asn1 srslog srsran_support gtest gtest_main) +target_link_libraries(asn1_cause_conversion_test ngap_asn1 f1ap_asn1 e1ap_asn1 srslog srsran_ran srsran_support gtest gtest_main) gtest_discover_tests(asn1_cause_conversion_test) diff --git a/tests/unittests/asn1/asn1_cause_conversion_test.cpp b/tests/unittests/asn1/asn1_cause_conversion_test.cpp index 3bed74ac6f..0ef082f883 100644 --- a/tests/unittests/asn1/asn1_cause_conversion_test.cpp +++ b/tests/unittests/asn1/asn1_cause_conversion_test.cpp @@ -11,6 +11,9 @@ #include "lib/e1ap/common/e1ap_asn1_converters.h" #include "lib/f1ap/cu_cp/f1ap_asn1_converters.h" #include "lib/ngap/ngap_asn1_converters.h" +#include "srsran/ran/cause/e1ap_cause_converters.h" +#include "srsran/ran/cause/f1ap_cause_converters.h" +#include "srsran/ran/cause/ngap_cause_converters.h" #include using namespace srsran; @@ -44,116 +47,116 @@ class asn1_cause_conversion_test : public ::testing::Test // test conversion from ngap asn1 TEST_F(asn1_cause_conversion_test, when_ngap_cause_received_then_conversion_to_common_cause_successful) { - asn1::ngap::cause_c ngap_cause; - cause_t cause; - - ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::unspecified; - cause = asn1_to_cause(ngap_cause); - ASSERT_TRUE(variant_holds_alternative(cause)); - ASSERT_EQ(variant_get(cause), cause_radio_network_t::unspecified); - - ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::cell_not_available; - cause = asn1_to_cause(ngap_cause); - ASSERT_TRUE(variant_holds_alternative(cause)); - ASSERT_EQ(variant_get(cause), cause_radio_network_t::cell_not_available); - - ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::up_confidentiality_protection_not_possible; - cause = asn1_to_cause(ngap_cause); - ASSERT_TRUE(variant_holds_alternative(cause)); - ASSERT_EQ(variant_get(cause), - cause_radio_network_t::up_confidentiality_protection_not_possible); - - ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::ho_target_not_allowed; - cause = asn1_to_cause(ngap_cause); - ASSERT_TRUE(variant_holds_alternative(cause)); - ASSERT_EQ(variant_get(cause), cause_radio_network_t::ho_target_not_allowed); - - ngap_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::user_inactivity; - cause = asn1_to_cause(ngap_cause); - ASSERT_TRUE(variant_holds_alternative(cause)); - ASSERT_EQ(variant_get(cause), cause_radio_network_t::user_inactivity); - - ngap_cause.set_transport() = asn1::ngap::cause_transport_opts::unspecified; - cause = asn1_to_cause(ngap_cause); - ASSERT_TRUE(variant_holds_alternative(cause)); - ASSERT_EQ(variant_get(cause), cause_transport_t::unspecified); - - ngap_cause.set_nas() = asn1::ngap::cause_nas_opts::deregister; - cause = asn1_to_cause(ngap_cause); - ASSERT_TRUE(variant_holds_alternative(cause)); - ASSERT_EQ(variant_get(cause), cause_nas_t::deregister); - - ngap_cause.set_protocol() = asn1::ngap::cause_protocol_opts::msg_not_compatible_with_receiver_state; - cause = asn1_to_cause(ngap_cause); - ASSERT_TRUE(variant_holds_alternative(cause)); - ASSERT_EQ(variant_get(cause), cause_protocol_t::msg_not_compatible_with_receiver_state); - - ngap_cause.set_misc() = asn1::ngap::cause_misc_opts::unspecified; - cause = asn1_to_cause(ngap_cause); - ASSERT_TRUE(variant_holds_alternative(cause)); - ASSERT_EQ(variant_get(cause), cause_misc_t::unspecified); - - ngap_cause.set_misc() = asn1::ngap::cause_misc_opts::unknown_plmn_or_sn_pn; - cause = asn1_to_cause(ngap_cause); - ASSERT_TRUE(variant_holds_alternative(cause)); - ASSERT_EQ(variant_get(cause), cause_misc_t::unknown_plmn_or_sn_pn); + asn1::ngap::cause_c asn1_cause; + ngap_cause_t ngap_cause; + + asn1_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::unspecified; + ngap_cause = asn1_to_cause(asn1_cause); + ASSERT_TRUE(variant_holds_alternative(ngap_cause)); + ASSERT_EQ(variant_get(ngap_cause), ngap_cause_radio_network_t::unspecified); + + asn1_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::cell_not_available; + ngap_cause = asn1_to_cause(asn1_cause); + ASSERT_TRUE(variant_holds_alternative(ngap_cause)); + ASSERT_EQ(variant_get(ngap_cause), ngap_cause_radio_network_t::cell_not_available); + + asn1_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::up_confidentiality_protection_not_possible; + ngap_cause = asn1_to_cause(asn1_cause); + ASSERT_TRUE(variant_holds_alternative(ngap_cause)); + ASSERT_EQ(variant_get(ngap_cause), + ngap_cause_radio_network_t::up_confidentiality_protection_not_possible); + + asn1_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::ho_target_not_allowed; + ngap_cause = asn1_to_cause(asn1_cause); + ASSERT_TRUE(variant_holds_alternative(ngap_cause)); + ASSERT_EQ(variant_get(ngap_cause), ngap_cause_radio_network_t::ho_target_not_allowed); + + asn1_cause.set_radio_network() = asn1::ngap::cause_radio_network_opts::user_inactivity; + ngap_cause = asn1_to_cause(asn1_cause); + ASSERT_TRUE(variant_holds_alternative(ngap_cause)); + ASSERT_EQ(variant_get(ngap_cause), ngap_cause_radio_network_t::user_inactivity); + + asn1_cause.set_transport() = asn1::ngap::cause_transport_opts::unspecified; + ngap_cause = asn1_to_cause(asn1_cause); + ASSERT_TRUE(variant_holds_alternative(ngap_cause)); + ASSERT_EQ(variant_get(ngap_cause), ngap_cause_transport_t::unspecified); + + asn1_cause.set_nas() = asn1::ngap::cause_nas_opts::deregister; + ngap_cause = asn1_to_cause(asn1_cause); + ASSERT_TRUE(variant_holds_alternative(ngap_cause)); + ASSERT_EQ(variant_get(ngap_cause), cause_nas_t::deregister); + + asn1_cause.set_protocol() = asn1::ngap::cause_protocol_opts::msg_not_compatible_with_receiver_state; + ngap_cause = asn1_to_cause(asn1_cause); + ASSERT_TRUE(variant_holds_alternative(ngap_cause)); + ASSERT_EQ(variant_get(ngap_cause), cause_protocol_t::msg_not_compatible_with_receiver_state); + + asn1_cause.set_misc() = asn1::ngap::cause_misc_opts::unspecified; + ngap_cause = asn1_to_cause(asn1_cause); + ASSERT_TRUE(variant_holds_alternative(ngap_cause)); + ASSERT_EQ(variant_get(ngap_cause), ngap_cause_misc_t::unspecified); + + asn1_cause.set_misc() = asn1::ngap::cause_misc_opts::unknown_plmn_or_sn_pn; + ngap_cause = asn1_to_cause(asn1_cause); + ASSERT_TRUE(variant_holds_alternative(ngap_cause)); + ASSERT_EQ(variant_get(ngap_cause), ngap_cause_misc_t::unknown_plmn_or_sn_pn); } // test conversion to ngap asn1 TEST_F(asn1_cause_conversion_test, when_common_cause_received_then_conversion_to_ngap_cause_successful) { - cause_t cause; + ngap_cause_t cause; asn1::ngap::cause_c ngap_cause; - cause = cause_radio_network_t::unspecified; - ngap_cause = cause_to_ngap_asn1(cause); + cause = ngap_cause_radio_network_t::unspecified; + ngap_cause = cause_to_asn1(cause); ASSERT_EQ(ngap_cause.type(), asn1::ngap::cause_c::types::radio_network); ASSERT_EQ(ngap_cause.radio_network().value, asn1::ngap::cause_radio_network_opts::unspecified); - cause = cause_radio_network_t::unknown_local_ue_ngap_id; - ngap_cause = cause_to_ngap_asn1(cause); + cause = ngap_cause_radio_network_t::unknown_local_ue_ngap_id; + ngap_cause = cause_to_asn1(cause); ASSERT_EQ(ngap_cause.type(), asn1::ngap::cause_c::types::radio_network); ASSERT_EQ(ngap_cause.radio_network().value, asn1::ngap::cause_radio_network_opts::unknown_local_ue_ngap_id); - cause = cause_radio_network_t::ue_in_rrc_inactive_state_not_reachable; - ngap_cause = cause_to_ngap_asn1(cause); + cause = ngap_cause_radio_network_t::ue_in_rrc_inactive_state_not_reachable; + ngap_cause = cause_to_asn1(cause); ASSERT_EQ(ngap_cause.type(), asn1::ngap::cause_c::types::radio_network); ASSERT_EQ(ngap_cause.radio_network().value, asn1::ngap::cause_radio_network_opts::ue_in_rrc_inactive_state_not_reachable); - cause = cause_radio_network_t::encryption_algorithms_not_supported; - ngap_cause = cause_to_ngap_asn1(cause); + cause = srsran::e1ap_to_ngap_cause(e1ap_cause_t{e1ap_cause_radio_network_t::encryption_algorithms_not_supported}); + ngap_cause = cause_to_asn1(cause); ASSERT_EQ(ngap_cause.type(), asn1::ngap::cause_c::types::radio_network); ASSERT_EQ(ngap_cause.radio_network().value, asn1::ngap::cause_radio_network_opts::encryption_and_or_integrity_protection_algorithms_not_supported); - cause = cause_radio_network_t::rl_fail_rlc; - ngap_cause = cause_to_ngap_asn1(cause); + cause = f1ap_to_ngap_cause(f1ap_cause_radio_network_t::rl_fail_rlc); + ngap_cause = cause_to_asn1(cause); ASSERT_EQ(ngap_cause.type(), asn1::ngap::cause_c::types::radio_network); ASSERT_EQ(ngap_cause.radio_network().value, asn1::ngap::cause_radio_network_opts::radio_conn_with_ue_lost); - cause = cause_transport_t::unspecified; - ngap_cause = cause_to_ngap_asn1(cause); + cause = ngap_cause_transport_t::unspecified; + ngap_cause = cause_to_asn1(cause); ASSERT_EQ(ngap_cause.type(), asn1::ngap::cause_c::types::transport); ASSERT_EQ(ngap_cause.transport().value, asn1::ngap::cause_transport_opts::unspecified); cause = cause_nas_t::deregister; - ngap_cause = cause_to_ngap_asn1(cause); + ngap_cause = cause_to_asn1(cause); ASSERT_EQ(ngap_cause.type(), asn1::ngap::cause_c::types::nas); ASSERT_EQ(ngap_cause.nas().value, asn1::ngap::cause_nas_opts::deregister); cause = cause_protocol_t::msg_not_compatible_with_receiver_state; - ngap_cause = cause_to_ngap_asn1(cause); + ngap_cause = cause_to_asn1(cause); ASSERT_EQ(ngap_cause.type(), asn1::ngap::cause_c::types::protocol); ASSERT_EQ(ngap_cause.protocol().value, asn1::ngap::cause_protocol_opts::msg_not_compatible_with_receiver_state); - cause = cause_misc_t::unspecified; - ngap_cause = cause_to_ngap_asn1(cause); + cause = ngap_cause_misc_t::unspecified; + ngap_cause = cause_to_asn1(cause); ASSERT_EQ(ngap_cause.type(), asn1::ngap::cause_c::types::misc); ASSERT_EQ(ngap_cause.misc().value, asn1::ngap::cause_misc_opts::unspecified); - cause = cause_misc_t::unknown_plmn_or_sn_pn; - ngap_cause = cause_to_ngap_asn1(cause); + cause = ngap_cause_misc_t::unknown_plmn_or_sn_pn; + ngap_cause = cause_to_asn1(cause); ASSERT_EQ(ngap_cause.type(), asn1::ngap::cause_c::types::misc); ASSERT_EQ(ngap_cause.misc().value, asn1::ngap::cause_misc_opts::unknown_plmn_or_sn_pn); } @@ -162,47 +165,47 @@ TEST_F(asn1_cause_conversion_test, when_common_cause_received_then_conversion_to TEST_F(asn1_cause_conversion_test, when_f1ap_cause_received_then_conversion_to_common_cause_successful) { asn1::f1ap::cause_c f1ap_cause; - cause_t cause; + f1ap_cause_t cause; f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::unspecified; cause = asn1_to_cause(f1ap_cause); - ASSERT_TRUE(variant_holds_alternative(cause)); - ASSERT_EQ(variant_get(cause), cause_radio_network_t::unspecified); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), f1ap_cause_radio_network_t::unspecified); f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::cell_not_available; cause = asn1_to_cause(f1ap_cause); - ASSERT_TRUE(variant_holds_alternative(cause)); - ASSERT_EQ(variant_get(cause), cause_radio_network_t::cell_not_available); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), f1ap_cause_radio_network_t::cell_not_available); f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::normal_release; cause = asn1_to_cause(f1ap_cause); - ASSERT_TRUE(variant_holds_alternative(cause)); - ASSERT_EQ(variant_get(cause), cause_radio_network_t::normal_release); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), f1ap_cause_radio_network_t::normal_release); f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::gnb_cu_cell_capacity_exceeded; cause = asn1_to_cause(f1ap_cause); - ASSERT_TRUE(variant_holds_alternative(cause)); - ASSERT_EQ(variant_get(cause), cause_radio_network_t::gnb_cu_cell_capacity_exceeded); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), f1ap_cause_radio_network_t::gnb_cu_cell_capacity_exceeded); f1ap_cause.set_radio_network() = asn1::f1ap::cause_radio_network_opts::rl_fail_others; cause = asn1_to_cause(f1ap_cause); - ASSERT_TRUE(variant_holds_alternative(cause)); - ASSERT_EQ(variant_get(cause), cause_radio_network_t::rl_fail_others); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), f1ap_cause_radio_network_t::rl_fail_others); f1ap_cause.set_transport() = asn1::f1ap::cause_transport_opts::unspecified; cause = asn1_to_cause(f1ap_cause); - ASSERT_TRUE(variant_holds_alternative(cause)); - ASSERT_EQ(variant_get(cause), cause_transport_t::unspecified); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), f1ap_cause_transport_t::unspecified); f1ap_cause.set_transport() = asn1::f1ap::cause_transport_opts::unknown_tnl_address_for_iab; cause = asn1_to_cause(f1ap_cause); - ASSERT_TRUE(variant_holds_alternative(cause)); - ASSERT_EQ(variant_get(cause), cause_transport_t::unknown_tnl_address_for_iab); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), f1ap_cause_transport_t::unknown_tnl_address_for_iab); f1ap_cause.set_transport() = asn1::f1ap::cause_transport_opts::unknown_up_tnl_info_for_iab; cause = asn1_to_cause(f1ap_cause); - ASSERT_TRUE(variant_holds_alternative(cause)); - ASSERT_EQ(variant_get(cause), cause_transport_t::unknown_up_tnl_info_for_iab); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), f1ap_cause_transport_t::unknown_up_tnl_info_for_iab); f1ap_cause.set_protocol() = asn1::f1ap::cause_protocol_opts::semantic_error; cause = asn1_to_cause(f1ap_cause); @@ -223,61 +226,66 @@ TEST_F(asn1_cause_conversion_test, when_f1ap_cause_received_then_conversion_to_c // test conversion to f1ap asn1 TEST_F(asn1_cause_conversion_test, when_common_cause_received_then_conversion_to_f1ap_cause_successful) { - cause_t cause; + f1ap_cause_t cause; asn1::f1ap::cause_c f1ap_cause; - cause = cause_radio_network_t::unspecified; - f1ap_cause = cause_to_f1ap_asn1(cause); + cause = f1ap_cause_radio_network_t::unspecified; + f1ap_cause = cause_to_asn1(cause); ASSERT_EQ(f1ap_cause.type(), asn1::f1ap::cause_c::types::radio_network); ASSERT_EQ(f1ap_cause.radio_network().value, asn1::f1ap::cause_radio_network_opts::unspecified); - cause = cause_radio_network_t::cell_not_available; - f1ap_cause = cause_to_f1ap_asn1(cause); + cause = f1ap_cause_radio_network_t::cell_not_available; + f1ap_cause = cause_to_asn1(cause); ASSERT_EQ(f1ap_cause.type(), asn1::f1ap::cause_c::types::radio_network); ASSERT_EQ(f1ap_cause.radio_network().value, asn1::f1ap::cause_radio_network_opts::cell_not_available); - cause = cause_radio_network_t::normal_release; - f1ap_cause = cause_to_f1ap_asn1(cause); + cause = f1ap_cause_radio_network_t::normal_release; + f1ap_cause = cause_to_asn1(cause); ASSERT_EQ(f1ap_cause.type(), asn1::f1ap::cause_c::types::radio_network); ASSERT_EQ(f1ap_cause.radio_network().value, asn1::f1ap::cause_radio_network_opts::normal_release); - cause = cause_radio_network_t::gnb_cu_cell_capacity_exceeded; - f1ap_cause = cause_to_f1ap_asn1(cause); + cause = f1ap_cause_radio_network_t::gnb_cu_cell_capacity_exceeded; + f1ap_cause = cause_to_asn1(cause); ASSERT_EQ(f1ap_cause.type(), asn1::f1ap::cause_c::types::radio_network); ASSERT_EQ(f1ap_cause.radio_network().value, asn1::f1ap::cause_radio_network_opts::gnb_cu_cell_capacity_exceeded); - cause = cause_radio_network_t::rl_fail_others; - f1ap_cause = cause_to_f1ap_asn1(cause); + cause = f1ap_cause_radio_network_t::rl_fail_others; + f1ap_cause = cause_to_asn1(cause); ASSERT_EQ(f1ap_cause.type(), asn1::f1ap::cause_c::types::radio_network); ASSERT_EQ(f1ap_cause.radio_network().value, asn1::f1ap::cause_radio_network_opts::rl_fail_others); - cause = cause_transport_t::unspecified; - f1ap_cause = cause_to_f1ap_asn1(cause); + cause = f1ap_cause_transport_t::unspecified; + f1ap_cause = cause_to_asn1(cause); ASSERT_EQ(f1ap_cause.type(), asn1::f1ap::cause_c::types::transport); ASSERT_EQ(f1ap_cause.transport().value, asn1::f1ap::cause_transport_opts::unspecified); - cause = cause_transport_t::unknown_tnl_address_for_iab; - f1ap_cause = cause_to_f1ap_asn1(cause); + cause = f1ap_cause_transport_t::unknown_tnl_address_for_iab; + f1ap_cause = cause_to_asn1(cause); ASSERT_EQ(f1ap_cause.type(), asn1::f1ap::cause_c::types::transport); ASSERT_EQ(f1ap_cause.transport().value, asn1::f1ap::cause_transport_opts::unknown_tnl_address_for_iab); - cause = cause_transport_t::unknown_up_tnl_info_for_iab; - f1ap_cause = cause_to_f1ap_asn1(cause); + cause = f1ap_cause_transport_t::unknown_up_tnl_info_for_iab; + f1ap_cause = cause_to_asn1(cause); ASSERT_EQ(f1ap_cause.type(), asn1::f1ap::cause_c::types::transport); ASSERT_EQ(f1ap_cause.transport().value, asn1::f1ap::cause_transport_opts::unknown_up_tnl_info_for_iab); + cause = srsran::ngap_to_f1ap_cause(ngap_cause_t{cause_nas_t::normal_release}); + f1ap_cause = cause_to_asn1(cause); + ASSERT_EQ(f1ap_cause.type(), asn1::ngap::cause_c::types::radio_network); + ASSERT_EQ(f1ap_cause.radio_network().value, asn1::f1ap::cause_radio_network_opts::normal_release); + cause = cause_protocol_t::semantic_error; - f1ap_cause = cause_to_f1ap_asn1(cause); + f1ap_cause = cause_to_asn1(cause); ASSERT_EQ(f1ap_cause.type(), asn1::f1ap::cause_c::types::protocol); ASSERT_EQ(f1ap_cause.protocol().value, asn1::f1ap::cause_protocol_opts::semantic_error); cause = cause_misc_t::hardware_fail; - f1ap_cause = cause_to_f1ap_asn1(cause); + f1ap_cause = cause_to_asn1(cause); ASSERT_EQ(f1ap_cause.type(), asn1::f1ap::cause_c::types::misc); ASSERT_EQ(f1ap_cause.misc().value, asn1::f1ap::cause_misc_opts::hardware_fail); cause = cause_misc_t::unspecified; - f1ap_cause = cause_to_f1ap_asn1(cause); + f1ap_cause = cause_to_asn1(cause); ASSERT_EQ(f1ap_cause.type(), asn1::f1ap::cause_c::types::misc); ASSERT_EQ(f1ap_cause.misc().value, asn1::f1ap::cause_misc_opts::unspecified); } @@ -286,43 +294,43 @@ TEST_F(asn1_cause_conversion_test, when_common_cause_received_then_conversion_to TEST_F(asn1_cause_conversion_test, when_e1ap_cause_received_then_conversion_to_common_cause_successful) { asn1::e1ap::cause_c e1ap_cause; - cause_t cause; + e1ap_cause_t cause; e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::unspecified; cause = asn1_to_cause(e1ap_cause); - ASSERT_TRUE(variant_holds_alternative(cause)); - ASSERT_EQ(variant_get(cause), cause_radio_network_t::unspecified); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), e1ap_cause_radio_network_t::unspecified); e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::unknown_or_inconsistent_pair_of_ue_e1ap_id; cause = asn1_to_cause(e1ap_cause); - ASSERT_TRUE(variant_holds_alternative(cause)); - ASSERT_EQ(variant_get(cause), - cause_radio_network_t::unknown_or_inconsistent_pair_of_ue_e1ap_id); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), + e1ap_cause_radio_network_t::unknown_or_inconsistent_pair_of_ue_e1ap_id); e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::normal_release; cause = asn1_to_cause(e1ap_cause); - ASSERT_TRUE(variant_holds_alternative(cause)); - ASSERT_EQ(variant_get(cause), cause_radio_network_t::normal_release); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), e1ap_cause_radio_network_t::normal_release); e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::pdcp_cfg_not_supported; cause = asn1_to_cause(e1ap_cause); - ASSERT_TRUE(variant_holds_alternative(cause)); - ASSERT_EQ(variant_get(cause), cause_radio_network_t::pdcp_cfg_not_supported); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), e1ap_cause_radio_network_t::pdcp_cfg_not_supported); e1ap_cause.set_radio_network() = asn1::e1ap::cause_radio_network_opts::report_characteristic_empty; cause = asn1_to_cause(e1ap_cause); - ASSERT_TRUE(variant_holds_alternative(cause)); - ASSERT_EQ(variant_get(cause), cause_radio_network_t::report_characteristic_empty); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), e1ap_cause_radio_network_t::report_characteristic_empty); e1ap_cause.set_transport() = asn1::e1ap::cause_transport_opts::unspecified; cause = asn1_to_cause(e1ap_cause); - ASSERT_TRUE(variant_holds_alternative(cause)); - ASSERT_EQ(variant_get(cause), cause_transport_t::unspecified); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), e1ap_cause_transport_t::unspecified); e1ap_cause.set_transport() = asn1::e1ap::cause_transport_opts::unknown_tnl_address_for_iab; cause = asn1_to_cause(e1ap_cause); - ASSERT_TRUE(variant_holds_alternative(cause)); - ASSERT_EQ(variant_get(cause), cause_transport_t::unknown_tnl_address_for_iab); + ASSERT_TRUE(variant_holds_alternative(cause)); + ASSERT_EQ(variant_get(cause), e1ap_cause_transport_t::unknown_tnl_address_for_iab); e1ap_cause.set_protocol() = asn1::e1ap::cause_protocol_opts::semantic_error; cause = asn1_to_cause(e1ap_cause); @@ -343,57 +351,62 @@ TEST_F(asn1_cause_conversion_test, when_e1ap_cause_received_then_conversion_to_c // test conversion to e1ap asn1 TEST_F(asn1_cause_conversion_test, when_common_cause_received_then_conversion_to_e1ap_cause_successful) { - cause_t cause; + e1ap_cause_t cause; asn1::e1ap::cause_c e1ap_cause; - cause = cause_radio_network_t::unspecified; - e1ap_cause = cause_to_e1ap_asn1(cause); + cause = e1ap_cause_radio_network_t::unspecified; + e1ap_cause = cause_to_asn1(cause); ASSERT_EQ(e1ap_cause.type(), asn1::e1ap::cause_c::types::radio_network); ASSERT_EQ(e1ap_cause.radio_network().value, asn1::e1ap::cause_radio_network_opts::unspecified); - cause = cause_radio_network_t::unknown_or_inconsistent_pair_of_ue_e1ap_id; - e1ap_cause = cause_to_e1ap_asn1(cause); + cause = e1ap_cause_radio_network_t::unknown_or_inconsistent_pair_of_ue_e1ap_id; + e1ap_cause = cause_to_asn1(cause); ASSERT_EQ(e1ap_cause.type(), asn1::e1ap::cause_c::types::radio_network); ASSERT_EQ(e1ap_cause.radio_network().value, asn1::e1ap::cause_radio_network_opts::unknown_or_inconsistent_pair_of_ue_e1ap_id); - cause = cause_radio_network_t::normal_release; - e1ap_cause = cause_to_e1ap_asn1(cause); + cause = e1ap_cause_radio_network_t::normal_release; + e1ap_cause = cause_to_asn1(cause); ASSERT_EQ(e1ap_cause.type(), asn1::e1ap::cause_c::types::radio_network); ASSERT_EQ(e1ap_cause.radio_network().value, asn1::e1ap::cause_radio_network_opts::normal_release); - cause = cause_radio_network_t::pdcp_cfg_not_supported; - e1ap_cause = cause_to_e1ap_asn1(cause); + cause = e1ap_cause_radio_network_t::pdcp_cfg_not_supported; + e1ap_cause = cause_to_asn1(cause); ASSERT_EQ(e1ap_cause.type(), asn1::e1ap::cause_c::types::radio_network); ASSERT_EQ(e1ap_cause.radio_network().value, asn1::e1ap::cause_radio_network_opts::pdcp_cfg_not_supported); - cause = cause_radio_network_t::report_characteristic_empty; - e1ap_cause = cause_to_e1ap_asn1(cause); + cause = e1ap_cause_radio_network_t::report_characteristic_empty; + e1ap_cause = cause_to_asn1(cause); ASSERT_EQ(e1ap_cause.type(), asn1::e1ap::cause_c::types::radio_network); ASSERT_EQ(e1ap_cause.radio_network().value, asn1::e1ap::cause_radio_network_opts::report_characteristic_empty); - cause = cause_transport_t::unspecified; - e1ap_cause = cause_to_e1ap_asn1(cause); + cause = e1ap_cause_transport_t::unspecified; + e1ap_cause = cause_to_asn1(cause); ASSERT_EQ(e1ap_cause.type(), asn1::e1ap::cause_c::types::transport); ASSERT_EQ(e1ap_cause.transport().value, asn1::e1ap::cause_transport_opts::unspecified); - cause = cause_transport_t::unknown_tnl_address_for_iab; - e1ap_cause = cause_to_e1ap_asn1(cause); + cause = e1ap_cause_transport_t::unknown_tnl_address_for_iab; + e1ap_cause = cause_to_asn1(cause); ASSERT_EQ(e1ap_cause.type(), asn1::e1ap::cause_c::types::transport); ASSERT_EQ(e1ap_cause.transport().value, asn1::e1ap::cause_transport_opts::unknown_tnl_address_for_iab); + cause = srsran::ngap_to_e1ap_cause(ngap_cause_t{cause_nas_t::normal_release}); + e1ap_cause = cause_to_asn1(cause); + ASSERT_EQ(e1ap_cause.type(), asn1::ngap::cause_c::types::radio_network); + ASSERT_EQ(e1ap_cause.radio_network().value, asn1::e1ap::cause_radio_network_opts::normal_release); + cause = cause_protocol_t::semantic_error; - e1ap_cause = cause_to_e1ap_asn1(cause); + e1ap_cause = cause_to_asn1(cause); ASSERT_EQ(e1ap_cause.type(), asn1::e1ap::cause_c::types::protocol); ASSERT_EQ(e1ap_cause.protocol().value, asn1::e1ap::cause_protocol_opts::semantic_error); cause = cause_misc_t::hardware_fail; - e1ap_cause = cause_to_e1ap_asn1(cause); + e1ap_cause = cause_to_asn1(cause); ASSERT_EQ(e1ap_cause.type(), asn1::e1ap::cause_c::types::misc); ASSERT_EQ(e1ap_cause.misc().value, asn1::e1ap::cause_misc_opts::hardware_fail); cause = cause_misc_t::unspecified; - e1ap_cause = cause_to_e1ap_asn1(cause); + e1ap_cause = cause_to_asn1(cause); ASSERT_EQ(e1ap_cause.type(), asn1::e1ap::cause_c::types::misc); ASSERT_EQ(e1ap_cause.misc().value, asn1::e1ap::cause_misc_opts::unspecified); } diff --git a/tests/unittests/cu_cp/du_processor_test_messages.cpp b/tests/unittests/cu_cp/du_processor_test_messages.cpp index 2554175ab6..6703e68363 100644 --- a/tests/unittests/cu_cp/du_processor_test_messages.cpp +++ b/tests/unittests/cu_cp/du_processor_test_messages.cpp @@ -97,7 +97,7 @@ cu_cp_ue_context_release_command srsran::srs_cu_cp::generate_ue_context_release_ { cu_cp_ue_context_release_command ue_context_release_command = {}; ue_context_release_command.ue_index = ue_index; - ue_context_release_command.cause = cause_radio_network_t::unspecified; + ue_context_release_command.cause = ngap_cause_radio_network_t::unspecified; return ue_context_release_command; } @@ -155,8 +155,9 @@ cu_cp_pdu_session_resource_release_command srsran::srs_cu_cp::generate_pdu_sessi cmd.ue_index = uint_to_ue_index(0); cu_cp_pdu_session_res_to_release_item_rel_cmd pdu_session_res_to_release_item_rel_cmd; - pdu_session_res_to_release_item_rel_cmd.pdu_session_id = pdu_session_id; - pdu_session_res_to_release_item_rel_cmd.pdu_session_res_release_cmd_transfer.cause = cause_nas_t::unspecified; + pdu_session_res_to_release_item_rel_cmd.pdu_session_id = pdu_session_id; + pdu_session_res_to_release_item_rel_cmd.pdu_session_res_release_cmd_transfer.cause = + ngap_cause_radio_network_t::unspecified; cmd.pdu_session_res_to_release_list_rel_cmd.emplace(pdu_session_id, pdu_session_res_to_release_item_rel_cmd); @@ -206,7 +207,7 @@ srsran::srs_cu_cp::generate_pdu_session_resource_modification_with_qos_flow_remo // Add item to remove inexisting QoS flow. cu_cp_qos_flow_with_cause_item release_item; release_item.qos_flow_id = flow_id; - release_item.cause = cause_radio_network_t::unspecified; + release_item.cause = ngap_cause_radio_network_t::unspecified; transfer.qos_flow_to_release_list.emplace(release_item.qos_flow_id, release_item); modify_item.transfer = transfer; diff --git a/tests/unittests/cu_up/pdu_session_manager_test.cpp b/tests/unittests/cu_up/pdu_session_manager_test.cpp index ee10ce6dd0..faf832315e 100644 --- a/tests/unittests/cu_up/pdu_session_manager_test.cpp +++ b/tests/unittests/cu_up/pdu_session_manager_test.cpp @@ -202,11 +202,11 @@ TEST_F(pdu_session_manager_test, drb_create_with_one_qfi_which_is_already_mapped EXPECT_TRUE(mod_result.success); ASSERT_EQ(mod_result.drb_setup_results.size(), 1); EXPECT_FALSE(mod_result.drb_setup_results[0].success); - EXPECT_EQ(mod_result.drb_setup_results[0].cause, cause_t{cause_radio_network_t::unspecified}); + EXPECT_EQ(mod_result.drb_setup_results[0].cause, e1ap_cause_t{e1ap_cause_radio_network_t::unspecified}); ASSERT_EQ(mod_result.drb_setup_results[0].qos_flow_results.size(), 1); EXPECT_FALSE(mod_result.drb_setup_results[0].qos_flow_results[0].success); EXPECT_EQ(mod_result.drb_setup_results[0].qos_flow_results[0].cause, - cause_t{cause_radio_network_t::multiple_qos_flow_id_instances}); + e1ap_cause_t{e1ap_cause_radio_network_t::multiple_qos_flow_id_instances}); // validate pdu session is not disconnected from GTP-U gateway EXPECT_EQ(pdu_session_mng->get_nof_pdu_sessions(), 1); @@ -239,7 +239,7 @@ TEST_F(pdu_session_manager_test, drb_create_with_unknown_five_qi) ASSERT_EQ(setup_result.drb_setup_results.size(), 1); EXPECT_FALSE(setup_result.drb_setup_results[0].success); - EXPECT_EQ(setup_result.drb_setup_results[0].cause, cause_t{cause_radio_network_t::not_supported_5qi_value}); + EXPECT_EQ(setup_result.drb_setup_results[0].cause, e1ap_cause_t{e1ap_cause_radio_network_t::not_supported_5qi_value}); ASSERT_EQ(setup_result.drb_setup_results[0].qos_flow_results.size(), 0); } @@ -290,13 +290,14 @@ TEST_F(pdu_session_manager_test, drb_create_with_two_qfi_of_which_one_is_already EXPECT_TRUE(mod_result.success); ASSERT_EQ(mod_result.drb_setup_results.size(), 1); EXPECT_TRUE(mod_result.drb_setup_results[0].success); // success, since at least one QFI mapping was valid - EXPECT_EQ(mod_result.drb_setup_results[0].cause, cause_t{cause_radio_network_t::unspecified}); + EXPECT_EQ(mod_result.drb_setup_results[0].cause, e1ap_cause_t{e1ap_cause_radio_network_t::unspecified}); ASSERT_EQ(mod_result.drb_setup_results[0].qos_flow_results.size(), 2); EXPECT_FALSE(mod_result.drb_setup_results[0].qos_flow_results[0].success); // the first was invalid EXPECT_EQ(mod_result.drb_setup_results[0].qos_flow_results[0].cause, - cause_t{cause_radio_network_t::multiple_qos_flow_id_instances}); + e1ap_cause_t{e1ap_cause_radio_network_t::multiple_qos_flow_id_instances}); EXPECT_TRUE(mod_result.drb_setup_results[0].qos_flow_results[1].success); // the second was valid - EXPECT_EQ(mod_result.drb_setup_results[0].qos_flow_results[1].cause, cause_t{cause_radio_network_t::unspecified}); + EXPECT_EQ(mod_result.drb_setup_results[0].qos_flow_results[1].cause, + e1ap_cause_t{e1ap_cause_radio_network_t::unspecified}); // validate pdu session is not disconnected from GTP-U gateway EXPECT_EQ(pdu_session_mng->get_nof_pdu_sessions(), 1); diff --git a/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp b/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp index 70d3249e07..34289e4279 100644 --- a/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp +++ b/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp @@ -259,7 +259,7 @@ e1ap_bearer_context_release_command srsran::srs_cu_cp::generate_bearer_context_r { e1ap_bearer_context_release_command command; command.ue_index = ue_index; - command.cause = cause_radio_network_t::unspecified; + command.cause = e1ap_cause_radio_network_t::unspecified; return command; } diff --git a/tests/unittests/e1ap/cu_cp/e1ap_cu_cp_setup_procedure_test.cpp b/tests/unittests/e1ap/cu_cp/e1ap_cu_cp_setup_procedure_test.cpp index f5fa41e575..e94423a550 100644 --- a/tests/unittests/e1ap/cu_cp/e1ap_cu_cp_setup_procedure_test.cpp +++ b/tests/unittests/e1ap/cu_cp/e1ap_cu_cp_setup_procedure_test.cpp @@ -64,7 +64,7 @@ TEST_F(e1ap_cu_cp_test, when_received_cu_up_e1_setup_request_invalid_then_reject test_logger.info("TEST: Transmit CuUpE1SetupFailure message..."); cu_up_e1_setup_response msg = {}; msg.success = false; - msg.cause = cause_radio_network_t::unspecified; + msg.cause = e1ap_cause_radio_network_t::unspecified; e1ap->handle_cu_up_e1_setup_response(msg); // Check the generated PDU is indeed the E1 Setup failure diff --git a/tests/unittests/f1ap/cu_cp/f1ap_cu_ue_context_release_procedure_test.cpp b/tests/unittests/f1ap/cu_cp/f1ap_cu_ue_context_release_procedure_test.cpp index 4fa66e202b..7a332c09f7 100644 --- a/tests/unittests/f1ap/cu_cp/f1ap_cu_ue_context_release_procedure_test.cpp +++ b/tests/unittests/f1ap/cu_cp/f1ap_cu_ue_context_release_procedure_test.cpp @@ -29,7 +29,7 @@ TEST_F(f1ap_cu_test, when_ue_release_command_received_then_procedure_succeeds) test_logger.info("Starting UE Context Release procedure"); f1ap_ue_context_release_command f1ap_ue_ctxt_rel_cmd_msg; f1ap_ue_ctxt_rel_cmd_msg.ue_index = ue_index_t::min; - f1ap_ue_ctxt_rel_cmd_msg.cause = cause_radio_network_t::unspecified; + f1ap_ue_ctxt_rel_cmd_msg.cause = f1ap_cause_radio_network_t::unspecified; // launch F1 UE context release procedure async_task t = f1ap->handle_ue_context_release_command(f1ap_ue_ctxt_rel_cmd_msg); diff --git a/tests/unittests/ngap/ngap_nas_message_test.cpp b/tests/unittests/ngap/ngap_nas_message_test.cpp index 71729d6e9d..7de884415c 100644 --- a/tests/unittests/ngap/ngap_nas_message_test.cpp +++ b/tests/unittests/ngap/ngap_nas_message_test.cpp @@ -10,7 +10,7 @@ #include "ngap_test_helpers.h" #include "srsran/asn1/ngap/ngap_pdu_contents.h" -#include "srsran/ran/cause.h" +#include "srsran/ran/cause/ngap_cause.h" #include "srsran/support/async/async_test_utils.h" #include "srsran/support/test_utils.h" #include @@ -90,7 +90,7 @@ TEST_F(ngap_nas_message_routine_test, when_initial_context_setup_request_is_not_ // check that UE release was requested ASSERT_NE(du_processor_notifier->last_command.ue_index, ue_index_t::invalid); - ASSERT_EQ(du_processor_notifier->last_command.cause, cause_t{cause_nas_t::unspecified}); + ASSERT_EQ(du_processor_notifier->last_command.cause, ngap_cause_t{ngap_cause_radio_network_t::unspecified}); } /// Test DL NAS transport handling diff --git a/tests/unittests/ngap/test_helpers.h b/tests/unittests/ngap/test_helpers.h index 5bff4ea249..1c1e322de3 100644 --- a/tests/unittests/ngap/test_helpers.h +++ b/tests/unittests/ngap/test_helpers.h @@ -197,7 +197,7 @@ class dummy_ngap_du_processor_notifier : public ngap_du_processor_control_notifi if (last_request.pdu_session_res_setup_items.empty()) { cu_cp_pdu_session_res_setup_failed_item failed_item; failed_item.pdu_session_id = uint_to_pdu_session_id(1); - failed_item.unsuccessful_transfer.cause = cause_radio_network_t::unspecified; + failed_item.unsuccessful_transfer.cause = ngap_cause_radio_network_t::unspecified; res.pdu_session_res_failed_to_setup_items.emplace(failed_item.pdu_session_id, failed_item); } else { res = generate_cu_cp_pdu_session_resource_setup_response(uint_to_pdu_session_id(1)); From 9d44b36fad5d699a6fc8c30e06d33dd8c55ef2a0 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Mon, 4 Mar 2024 16:03:10 +0100 Subject: [PATCH 069/140] sched: allow using SearchSpace 1 in policy scheduler for reestablishment scenario --- lib/scheduler/policy/scheduler_time_rr.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/lib/scheduler/policy/scheduler_time_rr.cpp b/lib/scheduler/policy/scheduler_time_rr.cpp index 282e737faa..e3bfdeab6f 100644 --- a/lib/scheduler/policy/scheduler_time_rr.cpp +++ b/lib/scheduler/policy/scheduler_time_rr.cpp @@ -372,8 +372,7 @@ static alloc_outcome alloc_ul_ue(const ue& u, static_vector search_spaces = ue_cc.get_active_ul_search_spaces(pdcch_slot, preferred_dci_rnti_type); for (const search_space_info* ss : search_spaces) { - if (ss->cfg->is_search_space0() or - ss->cfg->get_id() != ue_cc.cfg().cfg_dedicated().init_dl_bwp.pdcch_cfg->search_spaces.back().get_id()) { + if (ss->cfg->is_search_space0()) { continue; } @@ -517,14 +516,14 @@ void scheduler_time_rr::dl_sched(ue_pdsch_allocator& pdsch_alloc, const unsigned dl_new_tx_max_nof_rbs_per_ue_per_slot = compute_max_nof_rbs_per_ue_per_slot(ues, true, res_grid, expert_cfg); - // Second, schedule UEs with SRB data. - auto srb_newtx_ue_function = [this, &res_grid, &pdsch_alloc, dl_new_tx_max_nof_rbs_per_ue_per_slot](const ue& u) { - return alloc_dl_ue(u, res_grid, pdsch_alloc, false, true, logger, dl_new_tx_max_nof_rbs_per_ue_per_slot); - }; - next_dl_ue_index = round_robin_apply(ues, next_dl_ue_index, srb_newtx_ue_function); - - // Then, schedule new transmissions. if (dl_new_tx_max_nof_rbs_per_ue_per_slot > 0) { + // Second, schedule UEs with SRB data. + auto srb_newtx_ue_function = [this, &res_grid, &pdsch_alloc, dl_new_tx_max_nof_rbs_per_ue_per_slot](const ue& u) { + return alloc_dl_ue(u, res_grid, pdsch_alloc, false, true, logger, dl_new_tx_max_nof_rbs_per_ue_per_slot); + }; + next_dl_ue_index = round_robin_apply(ues, next_dl_ue_index, srb_newtx_ue_function); + + // Then, schedule new transmissions. auto tx_ue_function = [this, &res_grid, &pdsch_alloc, dl_new_tx_max_nof_rbs_per_ue_per_slot](const ue& u) { return alloc_dl_ue(u, res_grid, pdsch_alloc, false, false, logger, dl_new_tx_max_nof_rbs_per_ue_per_slot); }; From 2e98402ab0d3f9f53317a1ea55f03d2b903b85e8 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 29 Feb 2024 10:28:32 +0100 Subject: [PATCH 070/140] cu_cp,rrc: remove unused headers --- tests/unittests/rrc/rrc_ue_capability_transfer_proc_test.cpp | 5 +---- tests/unittests/rrc/rrc_ue_reconfig_proc_test.cpp | 4 +--- tests/unittests/rrc/rrc_ue_smc_proc_test.cpp | 5 +---- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/tests/unittests/rrc/rrc_ue_capability_transfer_proc_test.cpp b/tests/unittests/rrc/rrc_ue_capability_transfer_proc_test.cpp index db1348ef19..4c452ebe56 100644 --- a/tests/unittests/rrc/rrc_ue_capability_transfer_proc_test.cpp +++ b/tests/unittests/rrc/rrc_ue_capability_transfer_proc_test.cpp @@ -10,10 +10,7 @@ #include "rrc_ue_test_helpers.h" #include "rrc_ue_test_messages.h" -#include "srsran/adt/byte_buffer.h" -#include "srsran/rrc/rrc_du_factory.h" -#include "srsran/support/async/fifo_async_task_scheduler.h" -#include "srsran/support/test_utils.h" +#include "srsran/support/async/async_test_utils.h" #include using namespace srsran; diff --git a/tests/unittests/rrc/rrc_ue_reconfig_proc_test.cpp b/tests/unittests/rrc/rrc_ue_reconfig_proc_test.cpp index 3a322f51df..9508746fce 100644 --- a/tests/unittests/rrc/rrc_ue_reconfig_proc_test.cpp +++ b/tests/unittests/rrc/rrc_ue_reconfig_proc_test.cpp @@ -10,9 +10,7 @@ #include "rrc_ue_test_helpers.h" #include "rrc_ue_test_messages.h" -#include "srsran/adt/byte_buffer.h" -#include "srsran/support/async/fifo_async_task_scheduler.h" -#include "srsran/support/test_utils.h" +#include "srsran/support/async/async_test_utils.h" #include using namespace srsran; diff --git a/tests/unittests/rrc/rrc_ue_smc_proc_test.cpp b/tests/unittests/rrc/rrc_ue_smc_proc_test.cpp index de92707f0b..824899ed41 100644 --- a/tests/unittests/rrc/rrc_ue_smc_proc_test.cpp +++ b/tests/unittests/rrc/rrc_ue_smc_proc_test.cpp @@ -10,10 +10,7 @@ #include "rrc_ue_test_helpers.h" #include "rrc_ue_test_messages.h" -#include "srsran/adt/byte_buffer.h" -#include "srsran/rrc/rrc_du_factory.h" -#include "srsran/support/async/fifo_async_task_scheduler.h" -#include "srsran/support/test_utils.h" +#include "srsran/support/async/async_test_utils.h" #include using namespace srsran; From 974405dd318c7938f9d2b889c589b022f7b65605 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Mon, 4 Mar 2024 16:36:41 +0100 Subject: [PATCH 071/140] cu_cp,rrc: handle pdcp failures --- lib/rrc/ue/adapters/pdcp_adapters.h | 40 +++++++++++-------- lib/rrc/ue/rrc_ue_message_handlers.cpp | 22 +++++++--- lib/rrc/ue/rrc_ue_message_senders.cpp | 10 ++++- lib/rrc/ue/rrc_ue_srb_context.h | 35 ++++++++++++++-- .../unittests/rrc/rrc_ue_setup_proc_test.cpp | 20 ++++++++++ tests/unittests/rrc/rrc_ue_test_helpers.h | 23 +++++++++-- 6 files changed, 118 insertions(+), 32 deletions(-) diff --git a/lib/rrc/ue/adapters/pdcp_adapters.h b/lib/rrc/ue/adapters/pdcp_adapters.h index eb1450723e..3a85b35c83 100644 --- a/lib/rrc/ue/adapters/pdcp_adapters.h +++ b/lib/rrc/ue/adapters/pdcp_adapters.h @@ -10,10 +10,9 @@ #pragma once -#include "srsran/f1ap/cu_cp/f1ap_cu.h" #include "srsran/pdcp/pdcp_rx.h" #include "srsran/pdcp/pdcp_tx.h" -#include "srsran/rrc/rrc.h" +#include "srsran/ran/cause/ngap_cause.h" namespace srsran { namespace srs_cu_cp { @@ -36,26 +35,30 @@ class pdcp_rrc_ue_rx_adapter : public pdcp_rx_upper_data_notifier class pdcp_rx_control_rrc_ue_adapter : public pdcp_rx_upper_control_notifier { public: - explicit pdcp_rx_control_rrc_ue_adapter() - { - // TODO: connect a RRC handler - srslog::fetch_basic_logger("PDCP").debug("No RRC handler for PDCP Rx control events. All events will be ignored."); - } + pdcp_rx_control_rrc_ue_adapter() = default; void on_protocol_failure() override { - srslog::fetch_basic_logger("PDCP").warning("Ignoring on_protocol_failure() from PDCP Rx: No RRC handler."); + srslog::fetch_basic_logger("PDCP").warning("Requesting UE release. Cause: Received protocol failure from PDCP Rx"); + cause = cause_protocol_t::unspecified; } void on_integrity_failure() override { - srslog::fetch_basic_logger("PDCP").warning("Ignoring on_integrity_failure() from PDCP Rx: No RRC handler."); + srslog::fetch_basic_logger("PDCP").warning("Requesting UE release. Cause: Received integrity failure from PDCP Rx"); + cause = cause_protocol_t::unspecified; } void on_max_count_reached() override { - srslog::fetch_basic_logger("PDCP").warning("Ignoring on_max_count_reached() from PDCP Rx: No RRC handler."); + srslog::fetch_basic_logger("PDCP").warning("Requesting UE release. Cause: Max count reached from PDCP Rx"); + cause = cause_protocol_t::unspecified; } + + ngap_cause_t get_failure_cause() { return cause; } + +private: + ngap_cause_t cause; }; /// Adapter between PDCP and RRC UE for DL PDUs @@ -81,21 +84,24 @@ class pdcp_rrc_ue_tx_adapter : public pdcp_tx_lower_notifier class pdcp_tx_control_rrc_ue_adapter : public pdcp_tx_upper_control_notifier { public: - explicit pdcp_tx_control_rrc_ue_adapter() - { - // TODO: connect a RRC handler - srslog::fetch_basic_logger("PDCP").debug("No RRC handler for PDCP Tx control events. All events will be ignored."); - } + pdcp_tx_control_rrc_ue_adapter() = default; void on_protocol_failure() override { - srslog::fetch_basic_logger("PDCP").warning("Ignoring on_protocol_failure() from PDCP Tx: No RRC handler."); + srslog::fetch_basic_logger("PDCP").warning("Requesting UE release. Cause: Received protocol failure from PDCP Tx"); + cause = cause_protocol_t::unspecified; } void on_max_count_reached() override { - srslog::fetch_basic_logger("PDCP").warning("Ignoring on_max_count_reached() from PDCP Tx: No RRC handler."); + srslog::fetch_basic_logger("PDCP").warning("Requesting UE release. Cause: Max count reached from PDCP Tx"); + cause = cause_protocol_t::unspecified; } + + ngap_cause_t get_failure_cause() { return cause; } + +private: + ngap_cause_t cause; }; } // namespace srs_cu_cp diff --git a/lib/rrc/ue/rrc_ue_message_handlers.cpp b/lib/rrc/ue/rrc_ue_message_handlers.cpp index e9ab4310fe..97e2476104 100644 --- a/lib/rrc/ue/rrc_ue_message_handlers.cpp +++ b/lib/rrc/ue/rrc_ue_message_handlers.cpp @@ -188,13 +188,15 @@ void rrc_ue_impl::handle_ul_dcch_pdu(const srb_id_t srb_id, byte_buffer pdcp_pdu } // Unpack PDCP PDU - byte_buffer rrc_pdu = context.srbs.at(srb_id).unpack_pdcp_pdu(std::move(pdcp_pdu)); - if (rrc_pdu.empty()) { - logger.log_warning("Dropping empty PDU. RX {}", srb_id); - logger.log_debug("original len={}, new_len={}", pdcp_pdu.length(), rrc_pdu.length()); + pdcp_result pdcp_unpacking_result = context.srbs.at(srb_id).unpack_pdcp_pdu(std::move(pdcp_pdu)); + if (!pdcp_unpacking_result.is_successful()) { + logger.log_info("Requesting UE release. Cause: PDCP unpacking failed with {}", + pdcp_unpacking_result.get_failure_cause()); + on_ue_release_required(pdcp_unpacking_result.get_failure_cause()); return; } + byte_buffer rrc_pdu = pdcp_unpacking_result.get_pdu(); handle_pdu(srb_id, std::move(rrc_pdu)); } @@ -333,9 +335,17 @@ rrc_ue_release_context rrc_ue_impl::get_rrc_ue_release_context() dl_dcch_msg.msg.set_c1().set_rrc_release().crit_exts.set_rrc_release(); // pack DL CCCH msg - release_context.rrc_release_pdu = + pdcp_result pdcp_packing_result = context.srbs.at(srb_id_t::srb1).pack_rrc_pdu(pack_into_pdu(dl_dcch_msg, "RRCRelease")); - release_context.srb_id = srb_id_t::srb1; + if (!pdcp_packing_result.is_successful()) { + logger.log_info("Requesting UE release. Cause: PDCP packing failed with {}", + pdcp_packing_result.get_failure_cause()); + on_ue_release_required(pdcp_packing_result.get_failure_cause()); + return release_context; + } + + release_context.rrc_release_pdu = pdcp_packing_result.get_pdu(); + release_context.srb_id = srb_id_t::srb1; // Log Tx message log_rrc_message(logger, Tx, release_context.rrc_release_pdu, dl_dcch_msg, "DCCH DL"); diff --git a/lib/rrc/ue/rrc_ue_message_senders.cpp b/lib/rrc/ue/rrc_ue_message_senders.cpp index 433d58bf16..d9b7ead47d 100644 --- a/lib/rrc/ue/rrc_ue_message_senders.cpp +++ b/lib/rrc/ue/rrc_ue_message_senders.cpp @@ -44,7 +44,15 @@ void rrc_ue_impl::send_dl_dcch(srb_id_t srb_id, const dl_dcch_msg_s& dl_dcch_msg log_rrc_message(logger, Tx, pdu, dl_dcch_msg, "DCCH DL"); // pack PDCP PDU and send down the stack - byte_buffer pdcp_pdu = context.srbs.at(srb_id).pack_rrc_pdu(std::move(pdu)); + auto pdcp_packing_result = context.srbs.at(srb_id).pack_rrc_pdu(std::move(pdu)); + if (!pdcp_packing_result.is_successful()) { + logger.log_info("Requesting UE release. Cause: PDCP packing failed with {}", + pdcp_packing_result.get_failure_cause()); + on_ue_release_required(pdcp_packing_result.get_failure_cause()); + return; + } + + byte_buffer pdcp_pdu = pdcp_packing_result.get_pdu(); logger.log_debug(pdcp_pdu.begin(), pdcp_pdu.end(), "TX {} PDU", context.ue_index, context.c_rnti, srb_id); f1ap_pdu_notifier.on_new_rrc_pdu(srb_id, std::move(pdcp_pdu)); } diff --git a/lib/rrc/ue/rrc_ue_srb_context.h b/lib/rrc/ue/rrc_ue_srb_context.h index eb1b53a5e9..bbbcc76b27 100644 --- a/lib/rrc/ue/rrc_ue_srb_context.h +++ b/lib/rrc/ue/rrc_ue_srb_context.h @@ -16,6 +16,17 @@ namespace srsran { namespace srs_cu_cp { +struct pdcp_result { + variant result; + + /// Whether the packing/unpacking was successful. + bool is_successful() const { return variant_holds_alternative(result); } + + ngap_cause_t get_failure_cause() const { return variant_get(result); } + + byte_buffer get_pdu() const { return byte_buffer{variant_get(result)}; } +}; + /// Additional context of a SRB containing notifiers to PDCP, i.e. SRB1 and SRB2. struct srb_pdcp_context { std::unique_ptr entity; @@ -94,17 +105,33 @@ class ue_srb_context } // Add ciphering and integrity protection to an RRC PDU. - byte_buffer pack_rrc_pdu(byte_buffer rrc_pdu) + pdcp_result pack_rrc_pdu(byte_buffer rrc_pdu) { pdcp_context.entity->get_tx_upper_data_interface().handle_sdu(std::move(rrc_pdu)); - return pdcp_context.pdcp_tx_notifier.get_pdcp_pdu(); + + byte_buffer packed_pdu = pdcp_context.pdcp_tx_notifier.get_pdcp_pdu(); + + // If the PDCP layer failed to pack the PDU, return the failure cause. + if (packed_pdu.empty()) { + return pdcp_result{pdcp_context.rrc_tx_control_notifier.get_failure_cause()}; + } + + return pdcp_result{std::move(packed_pdu)}; } // Decipher and verify integrity of an PDCP PDU. - byte_buffer unpack_pdcp_pdu(byte_buffer pdcp_pdu) + pdcp_result unpack_pdcp_pdu(byte_buffer pdcp_pdu) { pdcp_context.entity->get_rx_lower_interface().handle_pdu(byte_buffer_chain{std::move(pdcp_pdu)}); - return pdcp_context.rrc_rx_data_notifier.get_rrc_pdu(); + + byte_buffer unpacked_pdu = pdcp_context.rrc_rx_data_notifier.get_rrc_pdu(); + + // If the PDCP layer failed to unpack the PDU, return the failure cause. + if (unpacked_pdu.empty()) { + return pdcp_result{pdcp_context.rrc_rx_control_notifier.get_failure_cause()}; + } + + return pdcp_result{std::move(unpacked_pdu)}; } private: diff --git a/tests/unittests/rrc/rrc_ue_setup_proc_test.cpp b/tests/unittests/rrc/rrc_ue_setup_proc_test.cpp index bf366d4403..178a61db51 100644 --- a/tests/unittests/rrc/rrc_ue_setup_proc_test.cpp +++ b/tests/unittests/rrc/rrc_ue_setup_proc_test.cpp @@ -94,3 +94,23 @@ TEST_F(rrc_ue_setup, when_setup_complete_received_initial_ue_message_sent) check_initial_ue_message_sent(); } + +/// Test the correct handling of corrupted RRC setup complete message +TEST_F(rrc_ue_setup, when_integrity_failure_detected_then_ue_deleted) +{ + receive_setup_request(); + + // check if the RRC setup message was generated + ASSERT_EQ(get_srb0_pdu_type(), asn1::rrc_nr::dl_ccch_msg_type_c::c1_c_::types::rrc_setup); + + // check if SRB1 was created + check_srb1_exists(); + + receive_corrupted_setup_complete(); + + // tick timer until RRC setup complete timer fires + tick_timer(); + + // verify that RRC requested UE context release + check_ue_release_requested(); +} diff --git a/tests/unittests/rrc/rrc_ue_test_helpers.h b/tests/unittests/rrc/rrc_ue_test_helpers.h index 60d4215541..510c5f946a 100644 --- a/tests/unittests/rrc/rrc_ue_test_helpers.h +++ b/tests/unittests/rrc/rrc_ue_test_helpers.h @@ -18,7 +18,6 @@ #include "srsran/ran/subcarrier_spacing.h" #include "srsran/rrc/rrc_config.h" #include "srsran/rrc/rrc_du.h" -#include "srsran/support/async/async_test_utils.h" #include "srsran/support/executors/manual_task_worker.h" #include @@ -133,7 +132,7 @@ class rrc_ue_test_helper return dl_ccch.msg.c1().type(); } - srb_id_t get_last_srb() + srb_id_t get_last_srb() const { // generated PDU must not be empty EXPECT_GT(rrc_ue_f1ap_notifier.last_rrc_pdu.length(), 0); @@ -238,6 +237,12 @@ class rrc_ue_test_helper rrc_ue->get_ul_dcch_pdu_handler().handle_ul_dcch_pdu(srb_id_t::srb1, byte_buffer{rrc_setup_complete_pdu}); } + void receive_corrupted_setup_complete() + { + // inject corrupted RRC setup complete + rrc_ue->get_ul_dcch_pdu_handler().handle_ul_dcch_pdu(srb_id_t::srb1, byte_buffer{corrupted_rrc_setup_complete_pdu}); + } + void send_dl_info_transfer(byte_buffer nas_pdu) { // inject RRC setup complete @@ -284,7 +289,7 @@ class rrc_ue_test_helper void check_smc_pdu() { ASSERT_EQ(rrc_ue_f1ap_notifier.last_rrc_pdu, byte_buffer{rrc_smc_pdu}); } - void check_initial_ue_message_sent() { ASSERT_TRUE(rrc_ue_ngap_notifier.initial_ue_msg_received); } + void check_initial_ue_message_sent() const { ASSERT_TRUE(rrc_ue_ngap_notifier.initial_ue_msg_received); } void check_rrc_ue_enquiry_pdu(uint8_t transaction_id) { @@ -320,7 +325,7 @@ class rrc_ue_test_helper rrc_ue_cu_cp_notifier.add_ue_context(reest_context); } - void check_meas_results(const rrc_meas_results& meas_results) + static void check_meas_results(const rrc_meas_results& meas_results) { ASSERT_EQ(meas_results.meas_id, uint_to_meas_id(1)); ASSERT_EQ(meas_results.meas_result_serving_mo_list.size(), 1); @@ -423,6 +428,16 @@ class rrc_ue_test_helper 0x00, 0x05, 0x20, 0x2f, 0x89, 0x90, 0x00, 0x00, 0x11, 0x70, 0x7f, 0x07, 0x0c, 0x04, 0x01, 0x98, 0x0b, 0x01, 0x80, 0x10, 0x17, 0x40, 0x00, 0x09, 0x05, 0x30, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00}; + // UL-DCCH with corrupted RRC setup complete message + std::array corrupted_rrc_setup_complete_pdu = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xf1, 0x00, 0xc0, 0x47, 0xe0, 0x04, 0x13, + 0x90, 0x00, 0xbf, 0x20, 0x2f, 0x89, 0x98, 0x00, 0x04, 0x10, 0x00, 0x00, 0x00, 0xf2, 0xe0, 0x4f, 0x07, 0x0f, 0x07, + 0x07, 0x10, 0x05, 0xe5, 0xe0, 0x04, 0x13, 0x90, 0x00, 0xbf, 0x20, 0x2f, 0x89, 0x98, 0x00, 0x04, 0x10, 0x00, 0x00, + 0x00, 0xf1, 0x00, 0x10, 0x32, 0x01, 0x4f, 0x07, 0x0f, 0x07, 0x02, 0xf1, 0xb0, 0x80, 0x10, 0x02, 0x7d, 0xb0, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x10, 0x1b, 0x66, 0x90, 0x00, 0x00, 0x00, 0x00, 0x80, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x05, 0x20, 0x2f, 0x89, 0x90, 0x00, 0x00, 0x11, 0x70, 0x7f, 0x07, 0x0c, 0x04, 0x01, 0x98, 0x0b, 0x01, 0x80, + 0x10, 0x17, 0x40, 0x00, 0x09, 0x05, 0x30, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00}; + // DL-DCCH with RRC security mode command std::array rrc_smc_pdu = {0x0, 0x0, 0x22, 0x08, 0x10, 0xec, 0xf0, 0xef, 0x74}; From e82ba47d51222c535535855bc4d536535300b157 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 21 Feb 2024 10:01:49 +0100 Subject: [PATCH 072/140] support: implementation of intrusive_ptr and application in byte_buffer control block --- include/srsran/adt/byte_buffer.h | 18 ++- include/srsran/adt/detail/intrusive_ptr.h | 144 ++++++++++++++++++++++ lib/support/byte_buffer.cpp | 29 +++-- 3 files changed, 178 insertions(+), 13 deletions(-) create mode 100644 include/srsran/adt/detail/intrusive_ptr.h diff --git a/include/srsran/adt/byte_buffer.h b/include/srsran/adt/byte_buffer.h index 3ebb4847c2..11703ef309 100644 --- a/include/srsran/adt/byte_buffer.h +++ b/include/srsran/adt/byte_buffer.h @@ -11,6 +11,7 @@ #pragma once #include "srsran/adt/detail/byte_buffer_range_helpers.h" +#include "srsran/adt/detail/intrusive_ptr.h" #include "fmt/format.h" namespace srsran { @@ -149,10 +150,23 @@ class byte_buffer size_t pkt_len = 0; /// One of the segments shares the same memory block with the byte_buffer control block. node_t* segment_in_cb_memory_block = nullptr; + /// Intrusive ptr reference counter. + intrusive_ptr_atomic_ref_counter ref_count; void destroy_node(node_t* node) const; ~control_block(); + + private: + friend void intrusive_ptr_inc_ref(control_block* ptr) { ptr->ref_count.inc_ref(); } + friend void intrusive_ptr_dec_ref(control_block* ptr) + { + if (ptr->ref_count.dec_ref()) { + ptr->destroy_cb(); + } + } + + void destroy_cb(); }; /// Headroom given to the first segment of the byte_buffer. @@ -411,9 +425,7 @@ class byte_buffer static void warn_alloc_failure(); - // TODO: Optimize. shared_ptr<> has a lot of boilerplate we don't need. It is also hard to determine the size - // of the shared_ptr control block allocation and how much we need to discount in the segment. - std::shared_ptr ctrl_blk_ptr = nullptr; + intrusive_ptr ctrl_blk_ptr; }; /// \brief This class represents a sub-interval or make_slice of a potentially larger byte_buffer. diff --git a/include/srsran/adt/detail/intrusive_ptr.h b/include/srsran/adt/detail/intrusive_ptr.h new file mode 100644 index 0000000000..8f6890243f --- /dev/null +++ b/include/srsran/adt/detail/intrusive_ptr.h @@ -0,0 +1,144 @@ +/* + * + * 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 { + +class intrusive_ptr_atomic_ref_counter +{ +public: + void inc_ref() { ref_count.fetch_add(1, std::memory_order_relaxed); } + + bool unique() const { return ref_count.load(std::memory_order_relaxed) == 1; } + + bool dec_ref() { return ref_count.fetch_sub(1, std::memory_order_acq_rel) == 1; } + +private: + std::atomic ref_count{0}; +}; + +template +class intrusive_ptr +{ +public: + intrusive_ptr() = default; + + intrusive_ptr(T* ptr_, bool add_ref = true) : ptr(ptr_) + { + if (ptr != nullptr && add_ref) { + intrusive_ptr_inc_ref(ptr); + } + } + + intrusive_ptr(const intrusive_ptr& other) : ptr(other.ptr) + { + if (ptr != nullptr) { + intrusive_ptr_inc_ref(ptr); + } + } + + intrusive_ptr(intrusive_ptr&& other) noexcept : ptr(other.ptr) { other.ptr = nullptr; } + + ~intrusive_ptr() + { + if (ptr != nullptr) { + intrusive_ptr_dec_ref(ptr); + } + } + + intrusive_ptr& operator=(intrusive_ptr& other) + { + if (ptr != other.ptr) { + T* temp = ptr; + if (other.ptr != nullptr) { + intrusive_ptr_inc_ref(other.ptr); + } + ptr = other.ptr; + if (temp != nullptr) { + instrusive_ptr_dec_ref(temp); + } + } + } + + intrusive_ptr& operator=(intrusive_ptr&& other) noexcept + { + intrusive_ptr{std::move(other)}.swap(*this); + return *this; + } + + T& operator*() const { return *ptr; } + + T* operator->() const { return ptr; } + + T* get() const { return ptr; } + + void reset() { intrusive_ptr{}.swap(*this); } + + void reset(T* other) { intrusive_ptr{other}.swap(*this); } + + void swap(intrusive_ptr& other) noexcept + { + T* temp = ptr; + ptr = other.ptr; + other.ptr = temp; + } + + bool unique() const { return intrusive_ptr_is_unique(ptr); } + +private: + T* ptr = nullptr; +}; + +template +inline void swap(intrusive_ptr& lhs, intrusive_ptr& rhs) +{ + lhs.swap(rhs); +} + +template +inline bool operator==(const intrusive_ptr& lhs, const intrusive_ptr& rhs) +{ + return (lhs.get() == rhs.get()); +} + +template +inline bool operator==(const intrusive_ptr& lhs, U* rhs) +{ + return (lhs.get() == rhs); +} + +template +inline bool operator==(const intrusive_ptr& lhs, std::nullptr_t rhs) +{ + return (lhs.get() == rhs); +} + +template +inline bool operator!=(const intrusive_ptr& lhs, const intrusive_ptr& rhs) +{ + return (lhs.get() != rhs.get()); +} + +template +inline bool operator!=(const intrusive_ptr& lhs, U* rhs) +{ + return (lhs.get() != rhs); +} + +template +inline bool operator!=(const intrusive_ptr& lhs, std::nullptr_t rhs) +{ + return (lhs.get() != rhs); +} + +} // namespace srsran \ No newline at end of file diff --git a/lib/support/byte_buffer.cpp b/lib/support/byte_buffer.cpp index 7c9d8de80c..61bdcf5a0d 100644 --- a/lib/support/byte_buffer.cpp +++ b/lib/support/byte_buffer.cpp @@ -145,6 +145,12 @@ byte_buffer::control_block::~control_block() } } +void byte_buffer::control_block::destroy_cb() +{ + this->~control_block(); + detail::get_default_byte_buffer_segment_pool().deallocate_node(this); +} + bool byte_buffer::append(span bytes) { if (bytes.empty()) { @@ -205,7 +211,7 @@ bool byte_buffer::append(byte_buffer&& other) *this = std::move(other); return true; } - if (not other.ctrl_blk_ptr.unique()) { + if (not other.ctrl_blk_ptr->ref_count.unique()) { // Use lvalue append. return append(other); } @@ -239,8 +245,8 @@ bool byte_buffer::append(byte_buffer&& other) byte_buffer::node_t* byte_buffer::create_head_segment(size_t headroom) { - static auto& pool = detail::get_default_byte_buffer_segment_pool(); - static const size_t block_size = pool.memory_block_size(); + auto& pool = detail::get_default_byte_buffer_segment_pool(); + const size_t block_size = pool.memory_block_size(); // Allocate new node. void* mem_block = pool.allocate_node(block_size); @@ -250,9 +256,12 @@ byte_buffer::node_t* byte_buffer::create_head_segment(size_t headroom) return nullptr; } - // Create control block using allocator. + // Construct linear allocator pointing to allocated segment memory block. memory_arena_linear_allocator arena{mem_block, block_size}; - ctrl_blk_ptr = std::allocate_shared(control_block_allocator{arena}); + + // Create control block using allocator. + void* cb_region = arena.allocate(sizeof(control_block), alignof(control_block)); + ctrl_blk_ptr = new (cb_region) control_block{}; if (ctrl_blk_ptr == nullptr) { byte_buffer::warn_alloc_failure(); pool.deallocate_node(mem_block); @@ -260,11 +269,11 @@ byte_buffer::node_t* byte_buffer::create_head_segment(size_t headroom) } // For first segment of byte_buffer, add a headroom. - void* segment_start = arena.allocate(sizeof(node_t), alignof(node_t)); + void* segment_header_region = arena.allocate(sizeof(node_t), alignof(node_t)); srsran_assert(block_size > arena.offset, "The memory block provided by the pool is too small"); - size_t segment_size = block_size - arena.offset; - void* payload_start = arena.allocate(segment_size, 1); - auto* node = new (segment_start) + size_t segment_size = block_size - arena.offset; + void* payload_start = arena.allocate(segment_size, 1); + node_t* node = new (segment_header_region) node_t(span{static_cast(payload_start), segment_size}, std::min(headroom, segment_size)); // Register segment as sharing the same memory block with control block. @@ -375,7 +384,7 @@ bool byte_buffer::prepend(byte_buffer&& other) // the byte buffer is empty. Prepending is the same as appending. return append(std::move(other)); } - if (not other.ctrl_blk_ptr.unique()) { + if (not other.ctrl_blk_ptr->ref_count.unique()) { // Deep copy of segments. return prepend(other); } From 4d4ffa585460b0c3a8dc99bb30def9f870d5060e Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 21 Feb 2024 10:37:25 +0100 Subject: [PATCH 073/140] support: implementation of linear memory allocator --- .../fixed_size_memory_block_pool.h | 7 ++ .../memory_pool/linear_memory_allocator.h | 51 ++++++++ lib/support/byte_buffer.cpp | 114 +++--------------- 3 files changed, 72 insertions(+), 100 deletions(-) create mode 100644 include/srsran/support/memory_pool/linear_memory_allocator.h diff --git a/include/srsran/support/memory_pool/fixed_size_memory_block_pool.h b/include/srsran/support/memory_pool/fixed_size_memory_block_pool.h index 23b3ba0b1e..599b71d22f 100644 --- a/include/srsran/support/memory_pool/fixed_size_memory_block_pool.h +++ b/include/srsran/support/memory_pool/fixed_size_memory_block_pool.h @@ -209,6 +209,13 @@ class fixed_size_memory_block_pool return (w->local_cache.size() - 1) * block_batch_size + w->local_cache.back().size(); } + /// Check if the memory pool owns the given memory segment. + bool owns_segment(void* segment) const + { + uint8_t* ptr = static_cast(segment); + return ptr >= allocated_memory.data() and ptr < allocated_memory.data() + allocated_memory.size(); + } + private: struct worker_ctxt { /// Thread ID of the worker. diff --git a/include/srsran/support/memory_pool/linear_memory_allocator.h b/include/srsran/support/memory_pool/linear_memory_allocator.h new file mode 100644 index 0000000000..01247ed050 --- /dev/null +++ b/include/srsran/support/memory_pool/linear_memory_allocator.h @@ -0,0 +1,51 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +#include "srsran/support/memory_pool/memory_pool_utils.h" +#include "srsran/support/srsran_assert.h" +#include + +namespace srsran { + +/// \brief Linear allocator for a contiguous memory block. +/// +/// This type of allocator doesn't provide a deallocation mechanism. +class linear_memory_allocator +{ +public: + linear_memory_allocator(void* memory_resource, std::size_t memory_resource_size) : + mem_start(static_cast(memory_resource)), mem_res_size(memory_resource_size) + { + srsran_sanity_check(mem_start != nullptr or mem_res_size == 0, "Invalid memory resource"); + } + + std::size_t size() const { return mem_res_size; } + std::size_t nof_bytes_left() const { return mem_res_size - mem_offset; } + std::size_t nof_bytes_allocated() const { return mem_offset; } + + void* memory_resource_start() const { return mem_start; } + + void* allocate(std::size_t sz, std::size_t al) noexcept + { + void* p = align_next(mem_start + mem_offset, al); + mem_offset = (static_cast(p) - mem_start) + sz; + srsran_sanity_check(mem_offset <= mem_res_size, "Out of memory"); + return p; + } + +private: + uint8_t* mem_start; + std::size_t mem_res_size; + std::size_t mem_offset = 0; +}; + +} // namespace srsran diff --git a/lib/support/byte_buffer.cpp b/lib/support/byte_buffer.cpp index 61bdcf5a0d..695a3a70fb 100644 --- a/lib/support/byte_buffer.cpp +++ b/lib/support/byte_buffer.cpp @@ -10,6 +10,7 @@ #include "srsran/adt/byte_buffer.h" #include "srsran/adt/detail/byte_buffer_segment_pool.h" +#include "srsran/support/memory_pool/linear_memory_allocator.h" using namespace srsran; @@ -39,94 +40,7 @@ void srsran::init_byte_buffer_segment_pool(std::size_t nof_segments, std::size_t report_fatal_error_if_not(memory_block_size > 64U, "memory blocks must be larger than the segment control header"); } -namespace { - -/// \brief Linear allocator for memory_block obtained from byte_buffer_segment_pool. -struct memory_arena_linear_allocator { - /// Pointer to the memory block obtained from byte_buffer_segment_pool. - void* mem_block = nullptr; - /// Size of the memory block in bytes. - size_t mem_block_size; - /// Offset in bytes from the beginning of the memory block, determining where the next allocation will be made. - size_t offset = 0; - - memory_arena_linear_allocator(void* mem_block_, size_t mem_block_size_) noexcept : - mem_block(mem_block_), mem_block_size(mem_block_size_) - { - } - - void* allocate(size_t sz, size_t al) noexcept - { - void* p = align_next(static_cast(mem_block) + offset, al); - offset = (static_cast(p) - static_cast(mem_block)) + sz; - return p; - } - - bool empty() const { return mem_block == nullptr; } - - size_t space_left() const { return mem_block_size - offset; } -}; - -/// Allocator for byte_buffer control_block that will leverage the \c memory_arena_linear_allocator. -template -struct control_block_allocator { -public: - using value_type = T; - - template - struct rebind { - using other = control_block_allocator; - }; - - control_block_allocator(memory_arena_linear_allocator& arena_) noexcept : arena(&arena_), mem_block(arena->mem_block) - { - } - - control_block_allocator(const control_block_allocator& other) noexcept = default; - - template ::value, int> = 0> - control_block_allocator(const control_block_allocator& other) noexcept : - arena(other.arena), mem_block(other.mem_block) - { - } - - control_block_allocator& operator=(const control_block_allocator& other) noexcept = default; - - value_type* allocate(size_t n) noexcept - { - srsran_sanity_check(n == 1, "control_block_allocator can only allocate one control block at a time."); - srsran_sanity_check(arena != nullptr and not arena->empty(), "Memory arena is empty"); - srsran_assert(arena->space_left() >= sizeof(value_type), "control_block_allocator memory block size is too small."); - memory_arena_linear_allocator* arena_ptr = arena; - // This allocator is only used for one single allocation (the shared_ptr control block). The arena may become - // dangling after we exit the head_segment alloc function as well. So, it is safer to just set this pointer to null. - arena = nullptr; - - return static_cast(arena_ptr->allocate(sizeof(value_type), alignof(std::max_align_t))); - } - - void deallocate(value_type* p, size_t n) noexcept - { - // Note: at this stage the arena ptr is probably dangling. Do not touch it. - srsran_sanity_check(n == 1, "control_block_allocator can only deallocate one control block at a time."); - - // Note: The pointer p, while within the memory block, might be misaligned. For this reason, we stored the - // original memory block pointer, which we now use for the deallocation. - detail::get_default_byte_buffer_segment_pool().deallocate_node(mem_block); - } - - bool operator==(const control_block_allocator& other) const { return mem_block == other.mem_block; } - bool operator!=(const control_block_allocator& other) const { return !(*this == other); } - -private: - template - friend struct control_block_allocator; - - memory_arena_linear_allocator* arena = nullptr; - void* mem_block = nullptr; -}; - -} // namespace +// ------- byte_buffer class ------- void byte_buffer::control_block::destroy_node(node_t* node) const { @@ -257,7 +171,7 @@ byte_buffer::node_t* byte_buffer::create_head_segment(size_t headroom) } // Construct linear allocator pointing to allocated segment memory block. - memory_arena_linear_allocator arena{mem_block, block_size}; + linear_memory_allocator arena{mem_block, block_size}; // Create control block using allocator. void* cb_region = arena.allocate(sizeof(control_block), alignof(control_block)); @@ -269,11 +183,10 @@ byte_buffer::node_t* byte_buffer::create_head_segment(size_t headroom) } // For first segment of byte_buffer, add a headroom. - void* segment_header_region = arena.allocate(sizeof(node_t), alignof(node_t)); - srsran_assert(block_size > arena.offset, "The memory block provided by the pool is too small"); - size_t segment_size = block_size - arena.offset; - void* payload_start = arena.allocate(segment_size, 1); - node_t* node = new (segment_header_region) + void* segment_header_region = arena.allocate(sizeof(node_t), alignof(node_t)); + size_t segment_size = arena.nof_bytes_left(); + void* payload_start = arena.allocate(segment_size, 1); + node_t* node = new (segment_header_region) node_t(span{static_cast(payload_start), segment_size}, std::min(headroom, segment_size)); // Register segment as sharing the same memory block with control block. @@ -284,8 +197,8 @@ byte_buffer::node_t* byte_buffer::create_head_segment(size_t headroom) byte_buffer::node_t* byte_buffer::create_segment(size_t headroom) { - static auto& pool = detail::get_default_byte_buffer_segment_pool(); - static const size_t block_size = pool.memory_block_size(); + static auto& pool = detail::get_default_byte_buffer_segment_pool(); + const size_t block_size = pool.memory_block_size(); // Allocate memory block. void* mem_block = pool.allocate_node(block_size); @@ -294,10 +207,11 @@ byte_buffer::node_t* byte_buffer::create_segment(size_t headroom) return nullptr; } - memory_arena_linear_allocator arena{mem_block, block_size}; - void* segment_start = arena.allocate(sizeof(node_t), alignof(node_t)); - srsran_assert(block_size > arena.offset, "The memory block provided by the pool is too small"); - size_t segment_size = block_size - arena.offset; + // Create a linear allocator pointing to the allocated memory block. + linear_memory_allocator arena{mem_block, block_size}; + + void* segment_start = arena.allocate(sizeof(node_t), alignof(node_t)); + size_t segment_size = arena.nof_bytes_left(); void* payload_start = arena.allocate(segment_size, 1); return new (segment_start) node_t(span{static_cast(payload_start), segment_size}, std::min(headroom, segment_size)); From f0329fe8241830f474f2136863d196db72ff9d7c Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 21 Feb 2024 11:27:14 +0100 Subject: [PATCH 074/140] asn1: make asn1 unbounded octet string use heap in case the byte buffer pool is depleted --- include/srsran/adt/byte_buffer.h | 10 ++++-- include/srsran/asn1/asn1_utils.h | 2 +- lib/asn1/asn1_utils.cpp | 19 +++++++++++- lib/support/byte_buffer.cpp | 53 +++++++++++++++++++++++--------- 4 files changed, 66 insertions(+), 18 deletions(-) diff --git a/include/srsran/adt/byte_buffer.h b/include/srsran/adt/byte_buffer.h index 11703ef309..69aeb3ac63 100644 --- a/include/srsran/adt/byte_buffer.h +++ b/include/srsran/adt/byte_buffer.h @@ -152,6 +152,8 @@ class byte_buffer node_t* segment_in_cb_memory_block = nullptr; /// Intrusive ptr reference counter. intrusive_ptr_atomic_ref_counter ref_count; + /// Whether failures to allocate segments using pool should fallback to malloc. + bool malloc_fallback = false; void destroy_node(node_t* node) const; @@ -177,9 +179,13 @@ class byte_buffer using iterator = detail::byte_buffer_segment_list_byte_iterator; using const_iterator = detail::byte_buffer_segment_list_byte_const_iterator; + struct fallback_allocation_tag {}; + /// Creates an empty byte_buffer. byte_buffer() noexcept = default; + byte_buffer(fallback_allocation_tag tag) noexcept; + /// Explicit copy ctor. User should use copy() method for copy assignments. explicit byte_buffer(const byte_buffer&) noexcept = default; @@ -396,9 +402,9 @@ class byte_buffer private: bool has_ctrl_block() const { return ctrl_blk_ptr != nullptr; } - SRSRAN_NODISCARD node_t* create_head_segment(size_t headroom); + SRSRAN_NODISCARD node_t* create_head_segment(size_t headroom, bool use_fallback = false); - static SRSRAN_NODISCARD node_t* create_segment(size_t headroom); + SRSRAN_NODISCARD node_t* create_segment(size_t headroom); SRSRAN_NODISCARD bool append_segment(size_t headroom_suggestion); diff --git a/include/srsran/asn1/asn1_utils.h b/include/srsran/asn1/asn1_utils.h index b0b131759f..ada5a0e12c 100644 --- a/include/srsran/asn1/asn1_utils.h +++ b/include/srsran/asn1/asn1_utils.h @@ -857,7 +857,7 @@ class unbounded_octstring : public srsran::byte_buffer using srsran::byte_buffer::byte_buffer; unbounded_octstring(byte_buffer other) noexcept : srsran::byte_buffer(std::move(other)) {} - unbounded_octstring(const unbounded_octstring& other) noexcept : srsran::byte_buffer(other.deep_copy()) {} + unbounded_octstring(const unbounded_octstring& other) noexcept; unbounded_octstring(unbounded_octstring&& other) noexcept : srsran::byte_buffer(std::move(other)) {} unbounded_octstring& operator=(byte_buffer other) noexcept diff --git a/lib/asn1/asn1_utils.cpp b/lib/asn1/asn1_utils.cpp index 8e17170ff4..a4271e6815 100644 --- a/lib/asn1/asn1_utils.cpp +++ b/lib/asn1/asn1_utils.cpp @@ -1013,11 +1013,28 @@ void octet_string_helper::append_hex_string(byte_buffer& buf, const std::string& dyn_octstring ************************/ +template +unbounded_octstring::unbounded_octstring(const unbounded_octstring& other) noexcept : + srsran::byte_buffer(fallback_allocation_tag{}) +{ + for (span seg : other.segments()) { + bool success = append(seg); + // Since fallback_allocation_tag is used, the buffer should not fail to allocate + (void)success; + } +} + template unbounded_octstring& unbounded_octstring::operator=(const unbounded_octstring& other) noexcept { if (this != &other) { - *static_cast(this) = other.deep_copy(); + clear(); + *this = byte_buffer{fallback_allocation_tag{}}; + for (span seg : other.segments()) { + bool success = append(seg); + // Since fallback_allocation_tag is used, the buffer should not fail to allocate + (void)success; + } } return *this; } diff --git a/lib/support/byte_buffer.cpp b/lib/support/byte_buffer.cpp index 695a3a70fb..e9e0f6fc18 100644 --- a/lib/support/byte_buffer.cpp +++ b/lib/support/byte_buffer.cpp @@ -46,7 +46,11 @@ void byte_buffer::control_block::destroy_node(node_t* node) const { node->~node_t(); if (node != segment_in_cb_memory_block) { - detail::byte_buffer_segment_pool::get_instance().deallocate_node(node); + if (not this->malloc_fallback or detail::byte_buffer_segment_pool::get_instance().owns_segment(node)) { + detail::byte_buffer_segment_pool::get_instance().deallocate_node(node); + } else { + delete[] reinterpret_cast(node); + } } } @@ -61,8 +65,23 @@ byte_buffer::control_block::~control_block() void byte_buffer::control_block::destroy_cb() { + bool pool_used = not this->malloc_fallback or detail::byte_buffer_segment_pool::get_instance().owns_segment(this); this->~control_block(); - detail::get_default_byte_buffer_segment_pool().deallocate_node(this); + if (pool_used) { + detail::get_default_byte_buffer_segment_pool().deallocate_node(this); + } else { + delete[] reinterpret_cast(this); + } +} + +// ----- byte_buffer ----- + +byte_buffer::byte_buffer(fallback_allocation_tag tag) noexcept +{ + node_t* n = create_head_segment(DEFAULT_FIRST_SEGMENT_HEADROOM, true); + + // Append new segment to linked list. + ctrl_blk_ptr->segments.push_back(*n); } bool byte_buffer::append(span bytes) @@ -157,7 +176,7 @@ bool byte_buffer::append(byte_buffer&& other) return true; } -byte_buffer::node_t* byte_buffer::create_head_segment(size_t headroom) +byte_buffer::node_t* byte_buffer::create_head_segment(size_t headroom, bool use_fallback) { auto& pool = detail::get_default_byte_buffer_segment_pool(); const size_t block_size = pool.memory_block_size(); @@ -165,9 +184,13 @@ byte_buffer::node_t* byte_buffer::create_head_segment(size_t headroom) // Allocate new node. void* mem_block = pool.allocate_node(block_size); if (mem_block == nullptr) { - // Pool is depleted. - byte_buffer::warn_alloc_failure(); - return nullptr; + if (not use_fallback) { + // Pool is depleted. + byte_buffer::warn_alloc_failure(); + return nullptr; + } + // Use heap as fallback. + mem_block = new uint8_t[block_size]; } // Construct linear allocator pointing to allocated segment memory block. @@ -176,11 +199,8 @@ byte_buffer::node_t* byte_buffer::create_head_segment(size_t headroom) // Create control block using allocator. void* cb_region = arena.allocate(sizeof(control_block), alignof(control_block)); ctrl_blk_ptr = new (cb_region) control_block{}; - if (ctrl_blk_ptr == nullptr) { - byte_buffer::warn_alloc_failure(); - pool.deallocate_node(mem_block); - return nullptr; - } + srsran_sanity_check(ctrl_blk_ptr != nullptr, "Something went wrong with the creation of the control block"); + ctrl_blk_ptr->malloc_fallback = use_fallback; // For first segment of byte_buffer, add a headroom. void* segment_header_region = arena.allocate(sizeof(node_t), alignof(node_t)); @@ -188,6 +208,7 @@ byte_buffer::node_t* byte_buffer::create_head_segment(size_t headroom) void* payload_start = arena.allocate(segment_size, 1); node_t* node = new (segment_header_region) node_t(span{static_cast(payload_start), segment_size}, std::min(headroom, segment_size)); + srsran_sanity_check(node != nullptr, "Something went wrong with the creation of the segment"); // Register segment as sharing the same memory block with control block. ctrl_blk_ptr->segment_in_cb_memory_block = node; @@ -197,14 +218,18 @@ byte_buffer::node_t* byte_buffer::create_head_segment(size_t headroom) byte_buffer::node_t* byte_buffer::create_segment(size_t headroom) { - static auto& pool = detail::get_default_byte_buffer_segment_pool(); + auto& pool = detail::get_default_byte_buffer_segment_pool(); const size_t block_size = pool.memory_block_size(); // Allocate memory block. void* mem_block = pool.allocate_node(block_size); if (mem_block == nullptr) { - byte_buffer::warn_alloc_failure(); - return nullptr; + if (not ctrl_blk_ptr->malloc_fallback) { + byte_buffer::warn_alloc_failure(); + return nullptr; + } + // Use malloc as fallback. + mem_block = new uint8_t[block_size]; } // Create a linear allocator pointing to the allocated memory block. From b7129c5650a59311aa21fffc47a4db272d0ed822 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 21 Feb 2024 15:52:11 +0100 Subject: [PATCH 075/140] support: add unit test for byte_buffer with fallback allocator --- include/srsran/adt/byte_buffer.h | 5 +-- include/srsran/asn1/asn1_utils.h | 4 +-- .../memory_pool/linear_memory_allocator.h | 2 +- lib/asn1/asn1_utils.cpp | 31 ++++++++---------- lib/support/byte_buffer.cpp | 20 ++++++++++-- tests/unittests/adt/CMakeLists.txt | 1 + tests/unittests/adt/byte_buffer_test.cpp | 32 +++++++++++++++++++ 7 files changed, 70 insertions(+), 25 deletions(-) diff --git a/include/srsran/adt/byte_buffer.h b/include/srsran/adt/byte_buffer.h index 69aeb3ac63..8863ea843b 100644 --- a/include/srsran/adt/byte_buffer.h +++ b/include/srsran/adt/byte_buffer.h @@ -184,8 +184,6 @@ class byte_buffer /// Creates an empty byte_buffer. byte_buffer() noexcept = default; - byte_buffer(fallback_allocation_tag tag) noexcept; - /// Explicit copy ctor. User should use copy() method for copy assignments. explicit byte_buffer(const byte_buffer&) noexcept = default; @@ -212,6 +210,9 @@ class byte_buffer /// Move constructor. byte_buffer(byte_buffer&& other) noexcept = default; + byte_buffer(fallback_allocation_tag tag, span other = {}) noexcept; + byte_buffer(fallback_allocation_tag tag, const byte_buffer& other) noexcept; + /// Copy assignment is disabled. Use std::move, .copy() or .deep_copy() instead. byte_buffer& operator=(const byte_buffer&) noexcept = delete; diff --git a/include/srsran/asn1/asn1_utils.h b/include/srsran/asn1/asn1_utils.h index ada5a0e12c..b51a60e1d8 100644 --- a/include/srsran/asn1/asn1_utils.h +++ b/include/srsran/asn1/asn1_utils.h @@ -817,7 +817,7 @@ class bounded_octstring { HANDLE_CODE(pack_length(bref, size(), LB, UB, aligned)); if (aligned) { - bref.align_bytes_zero(); + HANDLE_CODE(bref.align_bytes_zero()); } for (uint32_t i = 0; i < size(); ++i) { HANDLE_CODE(bref.pack(octets_[i], 8)); @@ -830,7 +830,7 @@ class bounded_octstring HANDLE_CODE(unpack_length(len, bref, LB, UB, aligned)); resize(len); if (aligned) { - bref.align_bytes(); + HANDLE_CODE(bref.align_bytes()); } for (uint32_t i = 0; i < size(); ++i) { HANDLE_CODE(bref.unpack(octets_[i], 8)); diff --git a/include/srsran/support/memory_pool/linear_memory_allocator.h b/include/srsran/support/memory_pool/linear_memory_allocator.h index 01247ed050..465ca61ab3 100644 --- a/include/srsran/support/memory_pool/linear_memory_allocator.h +++ b/include/srsran/support/memory_pool/linear_memory_allocator.h @@ -25,7 +25,7 @@ class linear_memory_allocator linear_memory_allocator(void* memory_resource, std::size_t memory_resource_size) : mem_start(static_cast(memory_resource)), mem_res_size(memory_resource_size) { - srsran_sanity_check(mem_start != nullptr or mem_res_size == 0, "Invalid memory resource"); + srsran_sanity_check(mem_start != nullptr and mem_res_size != 0, "Invalid memory resource"); } std::size_t size() const { return mem_res_size; } diff --git a/lib/asn1/asn1_utils.cpp b/lib/asn1/asn1_utils.cpp index a4271e6815..ec31d2dbba 100644 --- a/lib/asn1/asn1_utils.cpp +++ b/lib/asn1/asn1_utils.cpp @@ -940,7 +940,7 @@ void octet_string_helper::to_octet_string(srsran::span buf, uint64_t nu void octet_string_helper::to_octet_string(srsran::byte_buffer& buf, uint64_t number) { - buf.clear(); + buf = byte_buffer{byte_buffer::fallback_allocation_tag{}}; size_t nbytes = sizeof(number); for (uint32_t i = 0; i < nbytes; ++i) { if (not buf.append((number >> (uint64_t)((nbytes - 1 - i) * 8U)) & 0xffu)) { @@ -985,7 +985,7 @@ unsigned octet_string_helper::hex_string_to_octets(srsran::span buf, co { srsran_assert(buf.size() >= ceil_frac(str.size(), (size_t)2U), "out-of-bounds access"); if (str.size() % 2 != 0) { - log_warning("The provided hex string size={} is not a multiple of 2.", str.size()); + log_error("The provided hex string size={} is not a multiple of 2.", str.size()); } char cstr[] = "\0\0\0"; for (unsigned i = 0; i < str.size(); i += 2) { @@ -998,7 +998,7 @@ unsigned octet_string_helper::hex_string_to_octets(srsran::span buf, co void octet_string_helper::append_hex_string(byte_buffer& buf, const std::string& str) { if (str.size() % 2 != 0) { - log_warning("The provided hex string size={} is not a multiple of 2.", str.size()); + log_error("The provided hex string size={} is not a multiple of 2.", str.size()); } char cstr[] = "\0\0\0"; for (unsigned i = 0; i < str.size(); i += 2) { @@ -1015,26 +1015,17 @@ void octet_string_helper::append_hex_string(byte_buffer& buf, const std::string& template unbounded_octstring::unbounded_octstring(const unbounded_octstring& other) noexcept : - srsran::byte_buffer(fallback_allocation_tag{}) + // Use fallback allocator, because operator= should never fail. + srsran::byte_buffer(fallback_allocation_tag{}, other) { - for (span seg : other.segments()) { - bool success = append(seg); - // Since fallback_allocation_tag is used, the buffer should not fail to allocate - (void)success; - } } template unbounded_octstring& unbounded_octstring::operator=(const unbounded_octstring& other) noexcept { if (this != &other) { - clear(); - *this = byte_buffer{fallback_allocation_tag{}}; - for (span seg : other.segments()) { - bool success = append(seg); - // Since fallback_allocation_tag is used, the buffer should not fail to allocate - (void)success; - } + // Use fallback allocator, because operator= should never fail. + *this = byte_buffer{fallback_allocation_tag{}, other}; } return *this; } @@ -1051,7 +1042,7 @@ SRSASN_CODE unbounded_octstring::pack(bit_ref& bref) const { HANDLE_CODE(pack_length(bref, length(), aligned)); for (uint8_t b : *this) { - bref.pack(b, 8); + HANDLE_CODE(bref.pack(b, 8)); } return SRSASN_SUCCESS; } @@ -1079,8 +1070,12 @@ std::string unbounded_octstring::to_string() const template unbounded_octstring& unbounded_octstring::from_string(const std::string& hexstr) { - this->clear(); + // clears previous buffer. + *this = byte_buffer{byte_buffer::fallback_allocation_tag{}}; + + // appends hex string to buffer. octet_string_helper::append_hex_string(*this, hexstr); + return *this; } diff --git a/lib/support/byte_buffer.cpp b/lib/support/byte_buffer.cpp index e9e0f6fc18..c7d1d6bd4c 100644 --- a/lib/support/byte_buffer.cpp +++ b/lib/support/byte_buffer.cpp @@ -76,12 +76,28 @@ void byte_buffer::control_block::destroy_cb() // ----- byte_buffer ----- -byte_buffer::byte_buffer(fallback_allocation_tag tag) noexcept +byte_buffer::byte_buffer(fallback_allocation_tag tag, span other) noexcept { + // Append new head segment to linked list with fallback allocator mode. node_t* n = create_head_segment(DEFAULT_FIRST_SEGMENT_HEADROOM, true); + ctrl_blk_ptr->segments.push_back(*n); - // Append new segment to linked list. + bool var = this->append(other); + srsran_sanity_check(var, "Should never fail to append segment if fallback is enabled"); + (void)var; +} + +byte_buffer::byte_buffer(fallback_allocation_tag tag, const byte_buffer& other) noexcept +{ + // Append new head segment to linked list with fallback allocator mode. + node_t* n = create_head_segment(DEFAULT_FIRST_SEGMENT_HEADROOM, true); ctrl_blk_ptr->segments.push_back(*n); + + for (span seg : other.segments()) { + bool var = this->append(seg); + srsran_sanity_check(var, "Should never fail to append segment if fallback is enabled"); + (void)var; + } } bool byte_buffer::append(span bytes) diff --git a/tests/unittests/adt/CMakeLists.txt b/tests/unittests/adt/CMakeLists.txt index 75b036bfe6..009a6b68ac 100644 --- a/tests/unittests/adt/CMakeLists.txt +++ b/tests/unittests/adt/CMakeLists.txt @@ -22,6 +22,7 @@ add_executable(byte_buffer_test byte_buffer_chain_test.cpp) target_link_libraries(byte_buffer_test srslog srsran_support gtest gtest_main) add_test(byte_buffer_test byte_buffer_test) +set_tests_properties(byte_buffer_test PROPERTIES LABELS "tsan") gtest_discover_tests(byte_buffer_test) add_executable(ring_buffer_test ring_buffer_test.cpp blocking_queue_test.cpp concurrent_queue_test.cpp) diff --git a/tests/unittests/adt/byte_buffer_test.cpp b/tests/unittests/adt/byte_buffer_test.cpp index 9490113c1d..0326fb1406 100644 --- a/tests/unittests/adt/byte_buffer_test.cpp +++ b/tests/unittests/adt/byte_buffer_test.cpp @@ -852,6 +852,38 @@ TEST_P(byte_buffer_stress_tester, concurrent_alloc_dealloc_test) } } +TEST_F(byte_buffer_tester, concurrent_alloc_dealloc_test) +{ + const unsigned max_buffer_size = memory_block_size * 16; + std::vector randbytes = test_rgen::random_vector(max_buffer_size); + std::vector allocated_buffers; + + // Deplete the pool + while (true) { + byte_buffer pdu = byte_buffer{span{randbytes.data(), 10U}}; + if (pdu.empty()) { + break; + } + allocated_buffers.push_back(std::move(pdu)); + } + + // Pool is still empty. + byte_buffer pdu = byte_buffer{span{randbytes.data(), test_rgen::uniform_int(1U, max_buffer_size)}}; + ASSERT_TRUE(pdu.empty()); + + // Test if a span can be added to a byte_buffer with heap as fallback allocator. + size_t sz = test_rgen::uniform_int(1U, max_buffer_size); + pdu = byte_buffer{byte_buffer::fallback_allocation_tag{}, span{randbytes.data(), sz}}; + ASSERT_EQ(pdu.length(), sz); + span expected_bytes{randbytes.data(), sz}; + ASSERT_EQ(pdu, expected_bytes); + + // Test if a byte_buffer can be added to a byte_buffer with heap as fallback allocator. + pdu = byte_buffer{byte_buffer::fallback_allocation_tag{}, allocated_buffers.front()}; + ASSERT_EQ(pdu.length(), allocated_buffers.front().length()); + ASSERT_EQ(pdu, allocated_buffers.front()); +} + INSTANTIATE_TEST_SUITE_P(byte_buffer_test, one_vector_size_param_test, ::testing::Values(small_vec_size, large_vec_size, random_vec_size())); From 18e4335f14d6504b4bbc001a77d862fc1e84656e Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 21 Feb 2024 19:08:22 +0100 Subject: [PATCH 076/140] support: fix failing test due to bug in byte_buffer::resize --- include/srsran/adt/byte_buffer.h | 2 +- .../adt/detail/byte_buffer_segment_list.h | 3 ++ lib/support/byte_buffer.cpp | 30 +++++++++++-------- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/include/srsran/adt/byte_buffer.h b/include/srsran/adt/byte_buffer.h index 8863ea843b..6dab3d6a8d 100644 --- a/include/srsran/adt/byte_buffer.h +++ b/include/srsran/adt/byte_buffer.h @@ -403,7 +403,7 @@ class byte_buffer private: bool has_ctrl_block() const { return ctrl_blk_ptr != nullptr; } - SRSRAN_NODISCARD node_t* create_head_segment(size_t headroom, bool use_fallback = false); + SRSRAN_NODISCARD node_t* add_head_segment(size_t headroom, bool use_fallback = false); SRSRAN_NODISCARD node_t* create_segment(size_t headroom); diff --git a/include/srsran/adt/detail/byte_buffer_segment_list.h b/include/srsran/adt/detail/byte_buffer_segment_list.h index f7a967e91b..f0c939455a 100644 --- a/include/srsran/adt/detail/byte_buffer_segment_list.h +++ b/include/srsran/adt/detail/byte_buffer_segment_list.h @@ -238,6 +238,9 @@ class byte_buffer_segment_list_span_iterator_impl byte_buffer_segment_list_span_iterator_impl(NodeSegmentType* seg, size_t offset_, size_t size_) : current_segment(seg), offset(offset_), rem_bytes(size_) { + while (current_segment != nullptr and current_segment->length() == 0) { + current_segment = current_segment->next; + } srsran_assert(current_segment != nullptr or (offset == 0 and rem_bytes == 0), "Positive offset or length for empty segment"); srsran_assert(current_segment == nullptr or offset <= current_segment->length(), "Invalid offset"); diff --git a/lib/support/byte_buffer.cpp b/lib/support/byte_buffer.cpp index c7d1d6bd4c..e7f77520b7 100644 --- a/lib/support/byte_buffer.cpp +++ b/lib/support/byte_buffer.cpp @@ -79,8 +79,8 @@ void byte_buffer::control_block::destroy_cb() byte_buffer::byte_buffer(fallback_allocation_tag tag, span other) noexcept { // Append new head segment to linked list with fallback allocator mode. - node_t* n = create_head_segment(DEFAULT_FIRST_SEGMENT_HEADROOM, true); - ctrl_blk_ptr->segments.push_back(*n); + node_t* n = add_head_segment(DEFAULT_FIRST_SEGMENT_HEADROOM, true); + srsran_sanity_check(n != nullptr, "Should never fail to append segment if fallback is enabled"); bool var = this->append(other); srsran_sanity_check(var, "Should never fail to append segment if fallback is enabled"); @@ -90,8 +90,8 @@ byte_buffer::byte_buffer(fallback_allocation_tag tag, span other) byte_buffer::byte_buffer(fallback_allocation_tag tag, const byte_buffer& other) noexcept { // Append new head segment to linked list with fallback allocator mode. - node_t* n = create_head_segment(DEFAULT_FIRST_SEGMENT_HEADROOM, true); - ctrl_blk_ptr->segments.push_back(*n); + node_t* n = add_head_segment(DEFAULT_FIRST_SEGMENT_HEADROOM, true); + srsran_sanity_check(n != nullptr, "Should never fail to append segment if fallback is enabled"); for (span seg : other.segments()) { bool var = this->append(seg); @@ -192,7 +192,7 @@ bool byte_buffer::append(byte_buffer&& other) return true; } -byte_buffer::node_t* byte_buffer::create_head_segment(size_t headroom, bool use_fallback) +byte_buffer::node_t* byte_buffer::add_head_segment(size_t headroom, bool use_fallback) { auto& pool = detail::get_default_byte_buffer_segment_pool(); const size_t block_size = pool.memory_block_size(); @@ -229,6 +229,9 @@ byte_buffer::node_t* byte_buffer::create_head_segment(size_t headroom, bool use_ // Register segment as sharing the same memory block with control block. ctrl_blk_ptr->segment_in_cb_memory_block = node; + // Append new segment to linked list. + ctrl_blk_ptr->segments.push_back(*node); + return node; } @@ -260,12 +263,13 @@ byte_buffer::node_t* byte_buffer::create_segment(size_t headroom) bool byte_buffer::append_segment(size_t headroom_suggestion) { - node_t* segment = - not has_ctrl_block() ? create_head_segment(headroom_suggestion) : create_segment(headroom_suggestion); + if (not has_ctrl_block()) { + return add_head_segment(headroom_suggestion) != nullptr; + } + node_t* segment = create_segment(headroom_suggestion); if (segment == nullptr) { return false; } - // Append new segment to linked list. ctrl_blk_ptr->segments.push_back(*segment); return true; @@ -273,13 +277,13 @@ bool byte_buffer::append_segment(size_t headroom_suggestion) bool byte_buffer::prepend_segment(size_t headroom_suggestion) { - // Note: Add HEADROOM for first segment. - node_t* segment = - not has_ctrl_block() ? create_head_segment(headroom_suggestion) : create_segment(headroom_suggestion); + if (not has_ctrl_block()) { + return add_head_segment(headroom_suggestion) != nullptr; + } + node_t* segment = create_segment(headroom_suggestion); if (segment == nullptr) { return false; } - // Prepend new segment to linked list. ctrl_blk_ptr->segments.push_front(*segment); return true; @@ -472,7 +476,7 @@ bool byte_buffer::resize(size_t new_sz) } if (new_sz > prev_len) { for (size_t to_add = new_sz - prev_len; to_add > 0;) { - if (empty() or ctrl_blk_ptr->segments.tail->tailroom() == 0) { + if (not has_ctrl_block() or ctrl_blk_ptr->segments.tail->tailroom() == 0) { if (not append_segment(0)) { return false; } From 8eb7875fe414f5d4f65acb98783d2a80ccd36aec Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Thu, 22 Feb 2024 18:07:09 +0100 Subject: [PATCH 077/140] sched: fix byte buffer byte iterator --- include/srsran/adt/detail/byte_buffer_segment_list.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/include/srsran/adt/detail/byte_buffer_segment_list.h b/include/srsran/adt/detail/byte_buffer_segment_list.h index f0c939455a..49f99b6d47 100644 --- a/include/srsran/adt/detail/byte_buffer_segment_list.h +++ b/include/srsran/adt/detail/byte_buffer_segment_list.h @@ -128,13 +128,12 @@ class byte_buffer_segment_byte_iterator_impl using iterator_category = std::forward_iterator_tag; byte_buffer_segment_byte_iterator_impl() = default; - byte_buffer_segment_byte_iterator_impl(byte_buffer_segment_list::node_t* start_segment) : - current_segment(start_segment) - { - } - byte_buffer_segment_byte_iterator_impl(byte_buffer_segment_list::node_t* start_segment, size_t offset_) : + byte_buffer_segment_byte_iterator_impl(byte_buffer_segment_list::node_t* start_segment, size_t offset_ = 0) : current_segment(start_segment), offset(offset_) { + while (current_segment != nullptr and current_segment->length() == 0) { + current_segment = current_segment->next; + } } /// Conversion from iterators of uint8_t (iterator) to const uint8_t (const_iterator). @@ -250,6 +249,9 @@ class byte_buffer_segment_list_span_iterator_impl byte_buffer_segment_list_span_iterator_impl(const byte_buffer_segment_byte_iterator_impl& it, size_t size_) : byte_buffer_segment_list_span_iterator_impl(it.current_segment, it.offset, size_) { + while (current_segment != nullptr and current_segment->length() == 0) { + current_segment = current_segment->next; + } } /// Copy constructor. From 6cc5c1f672560e927fa3ed928a4ff9febb62b595 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 4 Mar 2024 16:06:17 +0100 Subject: [PATCH 078/140] adt: improve documentation of intrusive_ptr class --- include/srsran/adt/detail/intrusive_ptr.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/srsran/adt/detail/intrusive_ptr.h b/include/srsran/adt/detail/intrusive_ptr.h index 8f6890243f..8722da5003 100644 --- a/include/srsran/adt/detail/intrusive_ptr.h +++ b/include/srsran/adt/detail/intrusive_ptr.h @@ -14,6 +14,7 @@ namespace srsran { +/// \brief Atomic reference counter that can be used as a member of objects T of a intrusive_ptr. class intrusive_ptr_atomic_ref_counter { public: @@ -27,6 +28,10 @@ class intrusive_ptr_atomic_ref_counter std::atomic ref_count{0}; }; +/// \brief Smart pointer type where a reference counter for the managed object is stored in the object itself. +/// +/// The advantage of this class over a shared_ptr is its simplicity, avoiding two different memory regions for the +/// reference counter and the managed object. template class intrusive_ptr { From ef657f8254a57d6541689ba9e3a6db0af8a3e1f2 Mon Sep 17 00:00:00 2001 From: Joaquim Broquetas Date: Wed, 21 Feb 2024 15:45:31 +0100 Subject: [PATCH 079/140] gnb: initial radio gain console commands --- apps/gnb/gnb.cpp | 3 + apps/gnb/helpers/gnb_console_helper.cpp | 117 +++++++++++++++++- apps/gnb/helpers/gnb_console_helper.h | 7 ++ include/srsran/ru/ru_controller.h | 12 ++ lib/ru/dummy/ru_dummy_impl.h | 6 + lib/ru/generic/ru_controller_generic_impl.cpp | 10 ++ lib/ru/generic/ru_controller_generic_impl.h | 6 + lib/ru/ofh/ru_ofh_controller_impl.h | 6 + 8 files changed, 164 insertions(+), 3 deletions(-) diff --git a/apps/gnb/gnb.cpp b/apps/gnb/gnb.cpp index b0e7686352..fe1ad58a8c 100644 --- a/apps/gnb/gnb.cpp +++ b/apps/gnb/gnb.cpp @@ -506,6 +506,9 @@ int main(int argc, char** argv) variant_get(ru_cfg.config), gnb_cfg.log_cfg, workers, ru_ul_adapt, ru_timing_adapt); ru_object = create_generic_ru(variant_get(ru_cfg.config)); + + // Set the generic RU controller for the GNB console. + console.set_ru_controller(ru_object->get_controller()); } else { ru_dummy_dependencies ru_dependencies; configure_ru_dummy_executors_and_notifiers(variant_get(ru_cfg.config), diff --git a/apps/gnb/helpers/gnb_console_helper.cpp b/apps/gnb/helpers/gnb_console_helper.cpp index d4a4f00966..77acab9eee 100644 --- a/apps/gnb/helpers/gnb_console_helper.cpp +++ b/apps/gnb/helpers/gnb_console_helper.cpp @@ -15,12 +15,36 @@ #include "srsran/support/build_info/build_info.h" #include "srsran/support/io/io_broker.h" #include -#include #include #include using namespace srsran; +// Parses integer values from a console command. +template +static expected parse_int(const std::string& value) +{ + try { + return std::stoi(value); + } catch (const std::invalid_argument& e) { + return {e.what()}; + } catch (const std::out_of_range& e) { + return {e.what()}; + } +} + +// Parses floating point values from a console command and attempts to store them in a double. +static expected parse_double(const std::string& value) +{ + try { + return std::stod(value); + } catch (const std::invalid_argument& e) { + return {e.what()}; + } catch (const std::out_of_range& e) { + return {e.what()}; + } +} + gnb_console_helper::gnb_console_helper(io_broker& io_broker_, srslog::log_channel& log_chan_, bool autostart_stdout_metrics_) : @@ -89,12 +113,92 @@ void gnb_console_helper::stdin_handler(int fd) } } +void gnb_console_helper::handle_tx_gain_command(const std::list& gain_args) +{ + if (!radio_controller.has_value()) { + fmt::print("Interactive radio control is not supported for the current GNB configuration.\n"); + return; + } + + if (gain_args.size() != 2) { + fmt::print("Invalid TX gain command structure. Usage: tx_gain \n"); + return; + } + + expected port_id = parse_int(gain_args.front()); + if (port_id.is_error()) { + fmt::print("Invalid port ID.\n"); + return; + } + expected gain_dB = parse_double(gain_args.back()); + if (gain_dB.is_error()) { + fmt::print("Invalid gain value.\n"); + return; + } + + if (!radio_controller.value()->set_tx_gain(port_id.value(), gain_dB.value())) { + fmt::print("Setting TX gain was not successful. The radio may not support this feature.\n"); + return; + } + + fmt::print("Tx gain set to {} dB for port {}.\n", gain_dB.value(), port_id.value()); +} + +void gnb_console_helper::handle_rx_gain_command(const std::list& gain_args) +{ + if (!radio_controller.has_value()) { + fmt::print("Interactive radio control is not supported for the current GNB configuration.\n"); + return; + } + + if (gain_args.size() != 2) { + fmt::print("Invalid RX gain command structure. Usage: rx_gain \n"); + return; + } + + expected port_id = parse_int(gain_args.front()); + if (port_id.is_error()) { + fmt::print("Invalid port ID.\n"); + return; + } + expected gain_dB = parse_double(gain_args.back()); + if (gain_dB.is_error()) { + fmt::print("Invalid gain value.\n"); + return; + } + + if (!radio_controller.value()->set_rx_gain(port_id.value(), gain_dB.value())) { + fmt::print("Setting RX gain was not successful. The radio may not support this feature.\n"); + return; + } + + fmt::print("Rx gain set to {} dB for port {}.\n", gain_dB.value(), port_id.value()); +} + void gnb_console_helper::handle_command(const std::string& command) { + // Print help message if the command is empty. + if (command.empty()) { + print_help(); + return; + } + + // Break the command into a list of arguments. + std::list arg_list; + srsran::string_parse_list(command, ' ', arg_list); + + srsran_assert(!arg_list.empty(), "Parsing empty command argument list"); + if (command == "q") { raise(SIGTERM); } else if (command == "t") { metrics_plotter.toggle_print(); + } else if (arg_list.front() == "tx_gain") { + arg_list.pop_front(); + handle_tx_gain_command(arg_list); + } else if (arg_list.front() == "rx_gain") { + arg_list.pop_front(); + handle_rx_gain_command(arg_list); } else { print_help(); } @@ -103,8 +207,10 @@ void gnb_console_helper::handle_command(const std::string& command) void gnb_console_helper::print_help() { fmt::print("Available commands:\n"); - fmt::print("\tt: start/stop console trace\n"); - fmt::print("\tq: quit application\n"); + fmt::print("\tt: start/stop console trace\n"); + fmt::print("\tq: quit application\n"); + fmt::print("\ttx_gain : set Tx gain\n"); + fmt::print("\trx_gain : set Rx gain\n"); fmt::print("\n"); } @@ -113,6 +219,11 @@ void gnb_console_helper::set_cells(const span& cells_) cells = {cells_.begin(), cells_.end()}; } +void gnb_console_helper::set_ru_controller(ru_controller& controller) +{ + radio_controller.emplace(&controller); +} + void gnb_console_helper::on_app_starting() { fmt::print("\n--== srsRAN gNB (commit {}) ==--\n\n", get_build_hash()); diff --git a/apps/gnb/helpers/gnb_console_helper.h b/apps/gnb/helpers/gnb_console_helper.h index a2d207f1f5..4d62f0c52f 100644 --- a/apps/gnb/helpers/gnb_console_helper.h +++ b/apps/gnb/helpers/gnb_console_helper.h @@ -13,7 +13,9 @@ #include "metrics_plotter_json.h" #include "metrics_plotter_stdout.h" #include "srsran/du/du_cell_config.h" +#include "srsran/ru/ru_controller.h" #include "srsran/scheduler/scheduler_metrics.h" +#include namespace srsran { @@ -47,6 +49,10 @@ class gnb_console_helper : public app_state_notifier void on_app_stopping() override; void set_cells(const span& cells_); + void set_ru_controller(ru_controller& controller); + + void handle_tx_gain_command(const std::list& gain_args); + void handle_rx_gain_command(const std::list& gain_args); private: void stdin_handler(int fd); @@ -58,6 +64,7 @@ class gnb_console_helper : public app_state_notifier metrics_plotter_stdout metrics_plotter; metrics_plotter_json metrics_json; std::vector cells; + optional radio_controller; bool autostart_stdout_metrics = false; }; diff --git a/include/srsran/ru/ru_controller.h b/include/srsran/ru/ru_controller.h index d2c26a8a9f..288db72c85 100644 --- a/include/srsran/ru/ru_controller.h +++ b/include/srsran/ru/ru_controller.h @@ -31,6 +31,18 @@ class ru_controller /// \brief Stops the Radio Unit operation. /// \note Caller will be blocked until the controller is fully stopped. virtual void stop() = 0; + + /// \brief Sets the transmission gain for the specified port. + /// \param[in] port_id Port identifier. + /// \param[in] gain_dB Transmission gain in dB. + /// \return \c true if the operation is successful, \c false otherwise. + virtual bool set_tx_gain(unsigned port_id, double gain_dB) = 0; + + /// \brief Sets the receive gain for the specified port. + /// \param[in] port_id Port identifier. + /// \param[in] gain_dB Receive gain in dB. + /// \return \c true if the operation is successful, \c false otherwise. + virtual bool set_rx_gain(unsigned port_id, double gain_dB) = 0; }; } // namespace srsran diff --git a/lib/ru/dummy/ru_dummy_impl.h b/lib/ru/dummy/ru_dummy_impl.h index eef9771a45..bb74f25396 100644 --- a/lib/ru/dummy/ru_dummy_impl.h +++ b/lib/ru/dummy/ru_dummy_impl.h @@ -69,6 +69,12 @@ class ru_dummy_impl : public radio_unit, // See ru_controller for documentation. void stop() override; + // See interface for documentation. + bool set_tx_gain(unsigned port_id, double gain_dB) override { return false; } + + // See interface for documentation. + bool set_rx_gain(unsigned port_id, double gain_dB) override { return false; } + // See ru_downlink_plane_handler for documentation. void handle_dl_data(const resource_grid_context& context, const resource_grid_reader& grid) override { diff --git a/lib/ru/generic/ru_controller_generic_impl.cpp b/lib/ru/generic/ru_controller_generic_impl.cpp index 5934b16b01..10b9d0b434 100644 --- a/lib/ru/generic/ru_controller_generic_impl.cpp +++ b/lib/ru/generic/ru_controller_generic_impl.cpp @@ -45,3 +45,13 @@ void ru_controller_generic_impl::stop() low_phy->stop(); } } + +bool ru_controller_generic_impl::set_tx_gain(unsigned port_id, double gain_dB) +{ + return radio.get_management_plane().set_tx_gain(port_id, gain_dB); +} + +bool ru_controller_generic_impl::set_rx_gain(unsigned port_id, double gain_dB) +{ + return radio.get_management_plane().set_rx_gain(port_id, gain_dB); +} diff --git a/lib/ru/generic/ru_controller_generic_impl.h b/lib/ru/generic/ru_controller_generic_impl.h index 7cad208ba2..f5cb011d4e 100644 --- a/lib/ru/generic/ru_controller_generic_impl.h +++ b/lib/ru/generic/ru_controller_generic_impl.h @@ -32,6 +32,12 @@ class ru_controller_generic_impl : public ru_controller // See interface for documentation. void stop() override; + // See interface for documentation. + bool set_tx_gain(unsigned port_id, double gain_dB) override; + + // See interface for documentation. + bool set_rx_gain(unsigned port_id, double gain_dB) override; + private: std::vector low_phy_crtl; radio_session& radio; diff --git a/lib/ru/ofh/ru_ofh_controller_impl.h b/lib/ru/ofh/ru_ofh_controller_impl.h index fd66b54fbe..880102d950 100644 --- a/lib/ru/ofh/ru_ofh_controller_impl.h +++ b/lib/ru/ofh/ru_ofh_controller_impl.h @@ -32,6 +32,12 @@ class ru_ofh_controller_impl : public ru_controller // See interface for documentation. void stop() override; + // See interface for documentation. + bool set_tx_gain(unsigned port_id, double gain_dB) override { return false; } + + // See interface for documentation. + bool set_rx_gain(unsigned port_id, double gain_dB) override { return false; } + private: srslog::basic_logger& logger; std::vector sector_controllers; From 51c55f227bda2c135daeeb05b7091f1dcda2e015 Mon Sep 17 00:00:00 2001 From: qarlosalberto Date: Thu, 29 Feb 2024 14:06:02 +0100 Subject: [PATCH 080/140] ci: update retina --- .gitlab/ci/build.yml | 14 +++++++------- .gitlab/ci/e2e.yml | 2 ++ .gitlab/ci/e2e/.env | 2 +- tests/e2e/tests/ping.py | 1 + tests/e2e/tests/steps/configuration.py | 2 ++ 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 48246fd0c7..42d23401e6 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -632,7 +632,7 @@ smoke release update cache: - *cache_build_set artifacts: <<: *build_artifacts - expire_in: 1 day + expire_in: 3 day smoke relwithdeb update cache: extends: .smoke relwithdeb @@ -709,7 +709,7 @@ smoke valgrind update cache: SAVE_ARTIFACTS: "True" # Valgrind generates extra files artifacts: <<: *build_artifacts - expire_in: 1 day + expire_in: 3 day smoke asan: extends: .build_and_unit @@ -1716,7 +1716,7 @@ basic relwithdeb: SAVE_ARTIFACTS: "True" artifacts: <<: *build_artifacts - expire_in: 1 day + expire_in: 3 day basic tsan: extends: .smoke tsan @@ -1729,7 +1729,7 @@ basic tsan: SAVE_ARTIFACTS: "True" artifacts: <<: *build_artifacts - expire_in: 1 day + expire_in: 3 day basic asan: extends: smoke asan @@ -1743,7 +1743,7 @@ basic asan: tags: ["${AMD64_AVX2_TAG}"] artifacts: <<: *build_artifacts - expire_in: 1 day + expire_in: 3 day basic memcheck: extends: .smoke valgrind @@ -1756,7 +1756,7 @@ basic memcheck: SAVE_ARTIFACTS: "True" artifacts: <<: *build_artifacts - expire_in: 1 day + expire_in: 3 day basic avx512 dpdk: extends: .build_and_unit @@ -1786,7 +1786,7 @@ basic avx512 dpdk: tags: ["on-prem-amd64-avx2-avx512"] artifacts: <<: *build_artifacts - expire_in: 1 day + expire_in: 3 day ####### # Web # diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 7081b5d797..9a3b1dc23d 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -260,6 +260,7 @@ amari 32UE: variables: MARKERS: "zmq and not smoke" E2E_LOG_LEVEL: "info" + RETINA_ARGS: "gnb.all.pcap=True gnb.all.mac_enable=True gnb.all.rlc_enable=False" needs: - job: "basic relwithdeb" artifacts: true @@ -283,6 +284,7 @@ amari 32UE [reestablishment]: MARKERS: "zmq and not smoke" E2E_LOG_LEVEL: "info" KEYWORDS: reestablishment + RETINA_ARGS: "gnb.all.pcap=True gnb.all.mac_enable=True gnb.all.rlc_enable=False" allow_failure: true needs: - job: "basic relwithdeb" diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index 9c2cc255e3..2da4828430 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.43.1 +RETINA_VERSION=0.43.4 AMARISOFT_VERSION=2023-03-17 SRSUE_VERSION=23.11 OPEN5GS_VERSION=2.6.1 diff --git a/tests/e2e/tests/ping.py b/tests/e2e/tests/ping.py index a8c366fa19..0d4dcefd96 100644 --- a/tests/e2e/tests/ping.py +++ b/tests/e2e/tests/ping.py @@ -338,6 +338,7 @@ def _ping( global_timing_advance=global_timing_advance, time_alignment_calibration=time_alignment_calibration, gtpu_enable=True, + log_ip_level="debug", ) configure_artifacts( retina_data=retina_data, diff --git a/tests/e2e/tests/steps/configuration.py b/tests/e2e/tests/steps/configuration.py index f176981e4d..5485147737 100644 --- a/tests/e2e/tests/steps/configuration.py +++ b/tests/e2e/tests/steps/configuration.py @@ -33,6 +33,7 @@ def configure_test_parameters( gtpu_enable: Optional[bool] = None, common_search_space_enable: bool = False, prach_config_index: int = -1, + log_ip_level="", ): """ Configure test parameters @@ -47,6 +48,7 @@ def configure_test_parameters( "ssb_scs": common_scs, "bandwidth": bandwidth, "global_timing_advance": global_timing_advance, + "log_ip_level": log_ip_level, }, }, "gnb": { From ae4150783f6b14402a6ff99cb4ad8f377513455c Mon Sep 17 00:00:00 2001 From: faluco Date: Fri, 23 Feb 2024 12:33:26 +0100 Subject: [PATCH 081/140] byte_buffer: Introduce factory methods to create byte_buffers and related classes --- include/srsran/adt/byte_buffer.h | 50 ++++++++++++++++++++++++-- include/srsran/adt/byte_buffer_chain.h | 27 +++++++++++++- 2 files changed, 73 insertions(+), 4 deletions(-) diff --git a/include/srsran/adt/byte_buffer.h b/include/srsran/adt/byte_buffer.h index 6dab3d6a8d..8ab60e2c96 100644 --- a/include/srsran/adt/byte_buffer.h +++ b/include/srsran/adt/byte_buffer.h @@ -12,6 +12,7 @@ #include "srsran/adt/detail/byte_buffer_range_helpers.h" #include "srsran/adt/detail/intrusive_ptr.h" +#include "srsran/adt/expected.h" #include "fmt/format.h" namespace srsran { @@ -134,8 +135,9 @@ class byte_buffer_slice; /// \brief Byte sequence, which represents its data in memory via an intrusive linked list of memory chunks. /// /// This container is not contiguous in memory. -/// Default copy ctor and assignment is disabled in this container. The user should instead std::move to transfer -/// ownership, .copy() for shallow copies with shared ownership and .deep_copy() for byte-wise copies. +/// Default copy ctor, assignment and explicit construction is disabled in this container. The user should use the +/// provided factory methods to create objects, use std::move to transfer ownership, .copy() for shallow copies with +/// shared ownership and .deep_copy() for byte-wise copies. class byte_buffer { /// Node of linked list of byte buffer segments. @@ -194,9 +196,23 @@ class byte_buffer clear(); } } + /// Creates a byte_buffer with contents provided by a span of bytes. + static expected create(span bytes) + { + byte_buffer buf; + if (not buf.append(bytes)) { + return default_error_t{}; + } + return buf; + } /// Creates a byte_buffer with data initialized via a initializer list. byte_buffer(std::initializer_list lst) : byte_buffer(span{lst.begin(), lst.size()}) {} + /// Creates a byte_buffer with data initialized via a initializer list. + static expected create(std::initializer_list lst) + { + return create(span(lst.begin(), lst.size())); + } /// Creates a byte_buffer with data assigned from a range of bytes. template @@ -206,6 +222,16 @@ class byte_buffer clear(); } } + /// Creates a byte_buffer with data assigned from a range of bytes. + template + static expected create(It other_begin, It other_end) + { + byte_buffer buf; + if (not buf.append(other_begin, other_end)) { + return default_error_t{}; + } + return buf; + } /// Move constructor. byte_buffer(byte_buffer&& other) noexcept = default; @@ -270,7 +296,7 @@ class byte_buffer /// Appends an initializer list of bytes. SRSRAN_NODISCARD bool append(const std::initializer_list& bytes) { - return append(span{bytes.begin(), bytes.size()}); + return append(span(bytes.begin(), bytes.size())); } /// Appends bytes from another byte_buffer. This function may allocate new segments. @@ -456,8 +482,26 @@ class byte_buffer_slice explicit byte_buffer_slice(const byte_buffer_slice&) noexcept = default; byte_buffer_slice(byte_buffer_slice&&) noexcept = default; + byte_buffer_slice(span bytes) : byte_buffer_slice(byte_buffer{bytes}) {} + static expected create(span bytes) + { + auto buf = byte_buffer::create(bytes); + if (not buf) { + return default_error_t{}; + } + return byte_buffer_slice(std::move(buf.value())); + } + byte_buffer_slice(std::initializer_list bytes) : byte_buffer_slice(byte_buffer{bytes}) {} + static expected create(std::initializer_list bytes) + { + auto buf = byte_buffer::create(bytes); + if (not buf) { + return default_error_t{}; + } + return byte_buffer_slice(std::move(buf.value())); + } /// Conversion from byte_buffer to byte_buffer_slice via move. byte_buffer_slice(byte_buffer&& buf_) : buf(std::move(buf_)), sliced_view(buf) {} diff --git a/include/srsran/adt/byte_buffer_chain.h b/include/srsran/adt/byte_buffer_chain.h index b046465927..d2a4900d74 100644 --- a/include/srsran/adt/byte_buffer_chain.h +++ b/include/srsran/adt/byte_buffer_chain.h @@ -131,8 +131,9 @@ class byte_buffer_chain using iterator = iter_impl; using const_iterator = iter_impl; - /// \brief Creates an empty byte_buffer_chain. + /// Creates an empty byte_buffer_chain. byte_buffer_chain(); + static expected create() { return byte_buffer_chain{}; } ~byte_buffer_chain() { @@ -160,6 +161,15 @@ class byte_buffer_chain bool ret = append(std::move(buf_)); (void)ret; } + /// Creates a byte_buffer_chain from a byte_buffer. + static expected create(byte_buffer buf_) + { + byte_buffer_chain buf; + if (not buf.append(std::move(buf_))) { + return default_error_t{}; + } + return buf; + } /// Conversion from byte_buffer_slice to byte_buffer_chain. byte_buffer_chain(byte_buffer_slice&& buf_) : byte_buffer_chain() @@ -167,12 +177,26 @@ class byte_buffer_chain bool ret = append(std::move(buf_)); (void)ret; } + /// Creates a byte_buffer_chain from a byte_buffer_slice. + static expected create(byte_buffer_slice buf_) + { + byte_buffer_chain buf; + if (not buf.append(std::move(buf_))) { + return default_error_t{}; + } + return buf; + } /// Conversion from byte_buffer with specified offset and size to byte_buffer_chain. byte_buffer_chain(byte_buffer buf_, size_t start, size_t sz) : byte_buffer_chain(byte_buffer_slice(std::move(buf_), start, sz)) { } + /// Creates a byte_buffer_chain from byte_buffer with specified offset and size to byte_buffer_chain. + static expected create(byte_buffer buf_, size_t start, size_t sz) + { + return create(byte_buffer_slice(std::move(buf_), start, sz)); + } /// Default move assignment operator. byte_buffer_chain& operator=(byte_buffer_chain&& other) noexcept @@ -371,6 +395,7 @@ class byte_buffer_chain } // namespace srsran namespace fmt { + /// \brief Custom formatter for byte_buffer_chain. template <> struct formatter : public formatter { From 24bfa24d4083bb3ac737be68bcb0b0b7057f1976 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Fri, 1 Mar 2024 16:14:09 +0100 Subject: [PATCH 082/140] sched: generate k2 values less than nof. UL slots for UL heavy TDD configuration --- lib/scheduler/config/serving_cell_config_factory.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/scheduler/config/serving_cell_config_factory.cpp b/lib/scheduler/config/serving_cell_config_factory.cpp index bd26def06e..2c3cbd0a1c 100644 --- a/lib/scheduler/config/serving_cell_config_factory.cpp +++ b/lib/scheduler/config/serving_cell_config_factory.cpp @@ -312,7 +312,12 @@ srsran::config_helpers::generate_k2_candidates(cyclic_prefix cp, const tdd_ul_dl // allocations in the same slot for same UE. if (nof_dl_slots > nof_ul_slots) { break; - } else if (k2 > tdd_period_slots) { + } + // [Implementation-defined] For UL heavy TDD configuration, we avoid allocating PUSCH too far in the future. + // Reason: Scheduling PUSCH at slot k2 > nof_ul_slots results in CRC=KO when tested with COTS UE. + if (k2 > nof_ul_slots) { + // Remove last added PUSCH Time Domain resource since k2 > nof_ul_slots. + result.pop_back(); break; } } From d5ff29782c45ec0880111ea4c689915f31855583 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Wed, 28 Feb 2024 15:53:30 +0000 Subject: [PATCH 083/140] f1u: fixup log message --- .../f1u/local_connector/f1u_local_bearer_adapter.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/include/srsran/f1u/local_connector/f1u_local_bearer_adapter.h b/include/srsran/f1u/local_connector/f1u_local_bearer_adapter.h index f0ff835e73..a5d8772d48 100644 --- a/include/srsran/f1u/local_connector/f1u_local_bearer_adapter.h +++ b/include/srsran/f1u/local_connector/f1u_local_bearer_adapter.h @@ -28,27 +28,32 @@ class f1u_dl_local_adapter : public srs_cu_up::f1u_tx_pdu_notifier logger("CU-F1-U", {ue_index, drb_id, ul_tnl_info}) { } + void attach_du_handler(srs_du::f1u_rx_pdu_handler& handler_, const up_transport_layer_info& dl_tnl_info_) { handler = &handler_; dl_tnl_info.emplace(dl_tnl_info_); } + void detach_du_handler(const up_transport_layer_info& dl_tnl_info_) { if (dl_tnl_info == dl_tnl_info_) { handler = nullptr; dl_tnl_info.reset(); } else { - logger.log_info("Cannot dettach DU handler: DL-TEID does not match."); + logger.log_info("Cannot dettach DU bearer, DL-FTEID does not match. F-TEID={}, requested F-TEID={}", + dl_tnl_info, + dl_tnl_info_); } } + void on_new_pdu(nru_dl_message msg) override { if (handler == nullptr) { - logger.log_info("Cannot handle NR-U DL message: DU handler not attached."); + logger.log_info("Cannot handle NR-U DL message. DU bearer does not exist."); return; } - logger.log_debug("Passing PDU to DU handler. {}", dl_tnl_info); + logger.log_debug("Passing PDU to DU bearer. {}", dl_tnl_info); handler->handle_pdu(std::move(msg)); }; @@ -82,7 +87,7 @@ class f1u_ul_local_adapter : public srs_du::f1u_tx_pdu_notifier void on_new_pdu(nru_ul_message msg) override { if (handler == nullptr) { - srslog::fetch_basic_logger("DU-F1-U").info("Cannot handle NR-U UL message: CU handler not attached."); + logger.log_info("Cannot handle NR-U UL message. CU-UP bearer does not exist."); return; } handler->handle_pdu(std::move(msg)); From c6ec80cee6f7d801a9a1c86b60d3aa73dbd7a678 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Mon, 4 Mar 2024 18:13:43 +0100 Subject: [PATCH 084/140] rlc_rx: create byte_buffer_chain via factory functions --- lib/rlc/rlc_rx_am_entity.cpp | 2 +- lib/rlc/rlc_rx_tm_entity.cpp | 16 ++++++++++++---- lib/rlc/rlc_rx_um_entity.cpp | 17 +++++++++++++---- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/lib/rlc/rlc_rx_am_entity.cpp b/lib/rlc/rlc_rx_am_entity.cpp index a2e13c8c0b..8adcb83dce 100644 --- a/lib/rlc/rlc_rx_am_entity.cpp +++ b/lib/rlc/rlc_rx_am_entity.cpp @@ -487,7 +487,7 @@ expected rlc_rx_am_entity::reassemble_sdu(rlc_rx_am_sdu_info& return {default_error_t{}}; } - expected sdu = byte_buffer_chain(); // TODO USE byte_buffer_chain::create() + expected sdu = byte_buffer_chain::create(); if (!sdu) { logger.log_error("Failed to create SDU buffer. sn={} {}", sn, sdu_info); return {default_error_t{}}; diff --git a/lib/rlc/rlc_rx_tm_entity.cpp b/lib/rlc/rlc_rx_tm_entity.cpp index d54eb487cb..ecbc2daa6e 100644 --- a/lib/rlc/rlc_rx_tm_entity.cpp +++ b/lib/rlc/rlc_rx_tm_entity.cpp @@ -29,11 +29,19 @@ rlc_rx_tm_entity::rlc_rx_tm_entity(uint32_t du_index, void rlc_rx_tm_entity::handle_pdu(byte_buffer_slice buf) { - metrics.metrics_add_pdus(1, buf.length()); + size_t pdu_len = buf.length(); + metrics.metrics_add_pdus(1, pdu_len); pcap.push_pdu(pcap_context, buf); - logger.log_info(buf.begin(), buf.end(), "RX SDU. sdu_len={}", buf.length()); - metrics.metrics_add_sdus(1, buf.length()); - upper_dn.on_new_sdu(std::move(buf)); + expected sdu = byte_buffer_chain::create(std::move(buf)); + if (!sdu) { + logger.log_error("Dropped SDU, failed to create SDU buffer. sdu_len={}", pdu_len); + metrics.metrics_add_lost_pdus(1); + return; + } + + logger.log_info(sdu.value().begin(), sdu.value().end(), "RX SDU. sdu_len={}", sdu.value().length()); + metrics.metrics_add_sdus(1, sdu.value().length()); + upper_dn.on_new_sdu(std::move(sdu.value())); } diff --git a/lib/rlc/rlc_rx_um_entity.cpp b/lib/rlc/rlc_rx_um_entity.cpp index b88aa1ffd5..1aedb07f7a 100644 --- a/lib/rlc/rlc_rx_um_entity.cpp +++ b/lib/rlc/rlc_rx_um_entity.cpp @@ -70,13 +70,22 @@ void rlc_rx_um_entity::handle_pdu(byte_buffer_slice buf) // check if PDU contains a SN if (header.si == rlc_si_field::full_sdu) { + size_t sdu_len = payload.length(); + expected sdu = byte_buffer_chain::create(std::move(payload)); + if (!sdu) { + logger.log_error("Dropped SDU, failed to create SDU buffer. sdu_len={}", sdu_len); + metrics.metrics_add_lost_pdus(1); + return; + } + // deliver to upper layer - logger.log_info("RX SDU. sdu_len={}", payload.length()); - metrics.metrics_add_sdus(1, payload.length()); - upper_dn.on_new_sdu(std::move(payload)); + logger.log_info("RX SDU. sdu_len={}", sdu.value().length()); + metrics.metrics_add_sdus(1, sdu.value().length()); + upper_dn.on_new_sdu(std::move(sdu.value())); // Nothing else to do here ... return; } + if (sn_invalid_for_rx_buffer(header.sn)) { logger.log_info("Discarded PDU. sn={} payload_len={}", header.sn, payload.length()); // Nothing else to do here ... @@ -397,7 +406,7 @@ expected rlc_rx_um_entity::reassemble_sdu(rlc_rx_um_sdu_info& return {default_error_t{}}; } - expected sdu = byte_buffer_chain(); // TODO USE byte_buffer_chain::create() + expected sdu = byte_buffer_chain::create(); if (!sdu) { logger.log_error("Failed to create SDU buffer. sn={} {}", sn, sdu_info); return {default_error_t{}}; From 6084e684a51c9f288bb3f0da021bb8c76944a0cb Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Mon, 4 Mar 2024 18:16:12 +0100 Subject: [PATCH 085/140] rlc: stress test creates byte_buffer_chain via factory functions --- tests/integrationtests/rlc/rlc_stress_test_mac.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/integrationtests/rlc/rlc_stress_test_mac.cpp b/tests/integrationtests/rlc/rlc_stress_test_mac.cpp index d4991cae05..84611ecc0e 100644 --- a/tests/integrationtests/rlc/rlc_stress_test_mac.cpp +++ b/tests/integrationtests/rlc/rlc_stress_test_mac.cpp @@ -32,15 +32,19 @@ std::vector mac_dummy::run_tx_tti(uint32_t tti) // Request data to transmit if (bsr.load(std::memory_order_relaxed) > 0) { - unsigned nwritten = rlc_tx_lower->pull_pdu(tx_pdu); - byte_buffer_chain pdu = byte_buffer_slice{span(tx_pdu.data(), nwritten)}; + unsigned nwritten = rlc_tx_lower->pull_pdu(tx_pdu); + expected pdu = + byte_buffer_chain::create(byte_buffer_slice{span(tx_pdu.data(), nwritten)}); + if (!pdu) { + report_fatal_error_if_not(pdu, "Failed to create PDU buffer"); + } logger.log_debug("Pulled PDU. PDU size={}, MAC opportunity={}, buffer_state={}", - pdu.length(), + pdu.value().length(), opp_size, bsr.load(std::memory_order_relaxed)); // Push PDU in the list - if (pdu.length() > 0) { - pdu_list.push_back(std::move(pdu)); + if (pdu.value().length() > 0) { + pdu_list.push_back(std::move(pdu.value())); } } else { logger.log_debug("Did not pull a PDU. No data to TX."); From 25a4f91548d61985666b5f524b7fa357c6b9f19b Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 4 Mar 2024 16:00:37 +0100 Subject: [PATCH 086/140] du-high: stop DRB activity on F1AP UE context removal receival instead of after RRC Release is sent --- .../adapters/f1c_gateway_local_connector.cpp | 2 -- include/srsran/du_manager/du_manager.h | 3 +++ include/srsran/f1ap/du/f1ap_du.h | 7 +++++++ lib/du_high/adapters/f1ap_adapters.h | 5 +++++ lib/du_manager/du_manager_impl.cpp | 5 +++++ lib/du_manager/du_manager_impl.h | 2 ++ lib/du_manager/du_ue/du_ue.h | 6 ++++++ lib/du_manager/du_ue/du_ue_controller_impl.cpp | 17 +++++++++++++++++ lib/du_manager/du_ue/du_ue_controller_impl.h | 2 ++ lib/du_manager/du_ue/du_ue_manager.cpp | 9 +++++++++ lib/du_manager/du_ue/du_ue_manager.h | 3 +++ .../f1ap_du_ue_context_release_procedure.cpp | 3 +++ .../du_manager_procedure_test_helpers.h | 9 +++++---- tests/unittests/f1ap/du/f1ap_du_test_helpers.h | 2 ++ 14 files changed, 69 insertions(+), 6 deletions(-) diff --git a/apps/gnb/adapters/f1c_gateway_local_connector.cpp b/apps/gnb/adapters/f1c_gateway_local_connector.cpp index 6e37366b93..4acd54c7d7 100644 --- a/apps/gnb/adapters/f1c_gateway_local_connector.cpp +++ b/apps/gnb/adapters/f1c_gateway_local_connector.cpp @@ -30,8 +30,6 @@ class f1ap_pdu_pcap_notifier final : public f1ap_message_notifier void on_new_message(const f1ap_message& msg) override { - logger.debug("Received a PDU of type {}", msg.pdu.type().to_string()); - if (pcap_writer.is_write_enabled()) { byte_buffer buf; asn1::bit_ref bref(buf); diff --git a/include/srsran/du_manager/du_manager.h b/include/srsran/du_manager/du_manager.h index 7b686fab5f..c2553b7da7 100644 --- a/include/srsran/du_manager/du_manager.h +++ b/include/srsran/du_manager/du_manager.h @@ -52,6 +52,9 @@ class du_manager_configurator /// \brief Remove UE context from the DU. virtual async_task handle_ue_delete_request(const f1ap_ue_delete_request& request) = 0; + /// \brief Deactivate DRB activity for a given UE. + virtual async_task handle_ue_deactivation_request(du_ue_index_t ue_index) = 0; + /// \brief Handle the transfer of resources of old UE to new Reestablishing UE and deletion of the old UE context. virtual void handle_ue_reestablishment(du_ue_index_t new_ue_index, du_ue_index_t old_ue_index) = 0; }; diff --git a/include/srsran/f1ap/du/f1ap_du.h b/include/srsran/f1ap/du/f1ap_du.h index 29cb00582f..05841a9b95 100644 --- a/include/srsran/f1ap/du/f1ap_du.h +++ b/include/srsran/f1ap/du/f1ap_du.h @@ -173,6 +173,13 @@ class f1ap_du_configurator : public f1ap_task_scheduler /// \brief Request the update of the UE configuration in the DU. virtual async_task request_ue_removal(const f1ap_ue_delete_request& request) = 0; + /// \brief Request by the F1AP to the DU to deactivate the DRB activity for a given UE. + /// + /// This is generally called when the DU receives a request to remove a UE context, but it needs to flush first + /// any pending SRB PDUs. + /// \param ue_index Index of the UE for which the DRB deactivation is requested. + virtual async_task request_ue_drb_deactivation(du_ue_index_t ue_index) = 0; + /// \brief Notify DU that a given UE is performing RRC Reestablishment. virtual void notify_reestablishment_of_old_ue(du_ue_index_t new_ue_index, du_ue_index_t old_ue_index) = 0; diff --git a/lib/du_high/adapters/f1ap_adapters.h b/lib/du_high/adapters/f1ap_adapters.h index c502a9a73e..0e98ccc8f8 100644 --- a/lib/du_high/adapters/f1ap_adapters.h +++ b/lib/du_high/adapters/f1ap_adapters.h @@ -84,6 +84,11 @@ class f1ap_du_configurator_adapter : public f1ap_du_configurator return du_mng->handle_ue_delete_request(request); } + async_task request_ue_drb_deactivation(du_ue_index_t ue_index) override + { + return du_mng->handle_ue_deactivation_request(ue_index); + } + void notify_reestablishment_of_old_ue(du_ue_index_t new_ue_index, du_ue_index_t old_ue_index) override { du_mng->handle_ue_reestablishment(new_ue_index, old_ue_index); diff --git a/lib/du_manager/du_manager_impl.cpp b/lib/du_manager/du_manager_impl.cpp index 0438f1902a..39faf05bbb 100644 --- a/lib/du_manager/du_manager_impl.cpp +++ b/lib/du_manager/du_manager_impl.cpp @@ -143,6 +143,11 @@ async_task du_manager_impl::handle_ue_delete_request(const f1ap_ue_delete_ return ue_mng.handle_ue_delete_request(request); } +async_task du_manager_impl::handle_ue_deactivation_request(du_ue_index_t ue_index) +{ + return ue_mng.handle_ue_deactivation_request(ue_index); +} + void du_manager_impl::handle_ue_reestablishment(du_ue_index_t new_ue_index, du_ue_index_t old_ue_index) { ue_mng.handle_reestablishment_request(new_ue_index, old_ue_index); diff --git a/lib/du_manager/du_manager_impl.h b/lib/du_manager/du_manager_impl.h index 866a2be45c..15bc362324 100644 --- a/lib/du_manager/du_manager_impl.h +++ b/lib/du_manager/du_manager_impl.h @@ -49,6 +49,8 @@ class du_manager_impl final : public du_manager_interface async_task handle_ue_delete_request(const f1ap_ue_delete_request& request) override; + async_task handle_ue_deactivation_request(du_ue_index_t ue_index) override; + void handle_ue_reestablishment(du_ue_index_t new_ue_index, du_ue_index_t old_ue_index) override; size_t nof_ues() override; diff --git a/lib/du_manager/du_ue/du_ue.h b/lib/du_manager/du_ue/du_ue.h index abf505e367..64b2ace0f8 100644 --- a/lib/du_manager/du_ue/du_ue.h +++ b/lib/du_manager/du_ue/du_ue.h @@ -44,6 +44,12 @@ class du_ue_controller /// its bearers during the layer by layer UE context removal. virtual async_task disconnect_notifiers() = 0; + /// \brief Stop DRB activity and the detection of RLF for this UE. + /// + /// This method can be called when the DU receives a request to delete a UE context, but the UE is not yet in a + /// state where it is ready to be deleted (e.g. pending SRB PDUs). + virtual async_task handle_activity_stop_request() = 0; + /// \brief Schedule task for a given UE. virtual void schedule_async_task(async_task task) = 0; diff --git a/lib/du_manager/du_ue/du_ue_controller_impl.cpp b/lib/du_manager/du_ue/du_ue_controller_impl.cpp index a41ee5ac13..de9b179225 100644 --- a/lib/du_manager/du_ue/du_ue_controller_impl.cpp +++ b/lib/du_manager/du_ue/du_ue_controller_impl.cpp @@ -250,6 +250,21 @@ async_task du_ue_controller_impl::disconnect_notifiers() }); } +async_task du_ue_controller_impl::handle_activity_stop_request() +{ + // > Disconnect RLF notifiers. + rlf_handler->disconnect(); + + // > Disconnect bearers from within the UE execution context. + return dispatch_and_resume_on(cfg.services.ue_execs.ctrl_executor(ue_index), cfg.services.du_mng_exec, [this]() { + // > Disconnect DRBs. + for (auto& drb_pair : bearers.drbs()) { + du_ue_drb& drb = *drb_pair.second; + drb.stop(); + } + }); +} + void du_ue_controller_impl::handle_rlf_detection(rlf_cause cause) { rlf_handler->handle_rlf_detection(cause); @@ -263,6 +278,8 @@ void du_ue_controller_impl::handle_crnti_ce_detection() void du_ue_controller_impl::stop_drb_traffic() { // > Disconnect DRBs. + logger.debug("ue={}: Stopping DRB traffic...", ue_index); + // Note: We use an async task rather than just an execute call, to ensure that this task is not dispatched after // the UE has already been deleted. schedule_async_task( diff --git a/lib/du_manager/du_ue/du_ue_controller_impl.h b/lib/du_manager/du_ue/du_ue_controller_impl.h index 2a1d40b744..f73dac9c23 100644 --- a/lib/du_manager/du_ue/du_ue_controller_impl.h +++ b/lib/du_manager/du_ue/du_ue_controller_impl.h @@ -26,6 +26,8 @@ class du_ue_controller_impl final : public du_ue async_task disconnect_notifiers() override; + async_task handle_activity_stop_request() override; + void schedule_async_task(async_task task) override { ue_db.schedule_async_task(ue_index, std::move(task)); } void handle_rlf_detection(rlf_cause cause) override; diff --git a/lib/du_manager/du_ue/du_ue_manager.cpp b/lib/du_manager/du_ue/du_ue_manager.cpp index 26d101ae55..89bb88c2c9 100644 --- a/lib/du_manager/du_ue/du_ue_manager.cpp +++ b/lib/du_manager/du_ue/du_ue_manager.cpp @@ -91,6 +91,15 @@ async_task du_ue_manager::handle_ue_delete_request(const f1ap_ue_delete_re return launch_async(msg, *this, cfg); } +async_task du_ue_manager::handle_ue_deactivation_request(du_ue_index_t ue_index) +{ + if (not ue_db.contains(ue_index)) { + logger.warning("ue={}: UE deactivation request for inexistent UE index", ue_index); + return launch_no_op_task(); + } + return ue_db[ue_index].handle_activity_stop_request(); +} + void du_ue_manager::handle_reestablishment_request(du_ue_index_t new_ue_index, du_ue_index_t old_ue_index) { srsran_assert(ue_db.contains(new_ue_index), "Invalid UE index={}", new_ue_index); diff --git a/lib/du_manager/du_ue/du_ue_manager.h b/lib/du_manager/du_ue/du_ue_manager.h index 56b94190e0..8b6d8c805e 100644 --- a/lib/du_manager/du_ue/du_ue_manager.h +++ b/lib/du_manager/du_ue/du_ue_manager.h @@ -41,6 +41,9 @@ class du_ue_manager final : public du_ue_manager_repository /// \brief Handle the removal of an existing UE context by F1AP request. async_task handle_ue_delete_request(const f1ap_ue_delete_request& msg); + /// \brief Handle the deactivation of an existing UE context by F1AP request. + async_task handle_ue_deactivation_request(du_ue_index_t ue_index); + void handle_reestablishment_request(du_ue_index_t new_ue_index, du_ue_index_t old_ue_index); /// \brief Handle the configuration of an existing UE context by RIC request. diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_release_procedure.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_release_procedure.cpp index 8171f12e31..58468080db 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_release_procedure.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_release_procedure.cpp @@ -39,6 +39,9 @@ void f1ap_du_ue_context_release_procedure::operator()(coro_contextrrc_container_present) { // If the UE CONTEXT RELEASE COMMAND message contains the RRC-Container IE, the gNB-DU shall send the RRC // container to the UE via the SRB indicated by the SRB ID IE. diff --git a/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.h b/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.h index 5f6fd58fd2..d66285e6c0 100644 --- a/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.h +++ b/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.h @@ -38,10 +38,11 @@ class du_ue_dummy : public du_ue, public mac_ue_radio_link_notifier, public rlc_ ue_notifiers_disconnected = true; return launch_no_op_task(); } - void schedule_async_task(async_task task) override { ue_ctrl_loop->schedule(std::move(task)); } - void handle_rlf_detection(rlf_cause cause) override {} - void handle_crnti_ce_detection() override {} - void stop_drb_traffic() override {} + async_task handle_activity_stop_request() override { return launch_no_op_task(); } + void schedule_async_task(async_task task) override { ue_ctrl_loop->schedule(std::move(task)); } + void handle_rlf_detection(rlf_cause cause) override {} + void handle_crnti_ce_detection() override {} + void stop_drb_traffic() override {} mac_ue_radio_link_notifier& get_mac_rlf_notifier() override { return *this; } void on_rlf_detected() override {} void on_crnti_ce_received() override {} diff --git a/tests/unittests/f1ap/du/f1ap_du_test_helpers.h b/tests/unittests/f1ap/du/f1ap_du_test_helpers.h index 690666b002..278fe80c4c 100644 --- a/tests/unittests/f1ap/du/f1ap_du_test_helpers.h +++ b/tests/unittests/f1ap/du/f1ap_du_test_helpers.h @@ -104,6 +104,8 @@ class dummy_f1ap_du_configurator : public f1ap_du_configurator }); } + async_task request_ue_drb_deactivation(du_ue_index_t ue_index) override { return launch_no_op_task(); } + void notify_reestablishment_of_old_ue(du_ue_index_t new_ue_index, du_ue_index_t old_ue_index) override {} /// \brief Retrieve task scheduler specific to a given UE. From 31688423f157e31501cc243c7122b8152edbd093 Mon Sep 17 00:00:00 2001 From: ofontbach Date: Tue, 5 Mar 2024 11:05:38 +0100 Subject: [PATCH 087/140] phy: fixes pdsch processor vectortest for acc100 --- .../phy/upper/channel_processors/pdsch_processor_vectortest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unittests/phy/upper/channel_processors/pdsch_processor_vectortest.cpp b/tests/unittests/phy/upper/channel_processors/pdsch_processor_vectortest.cpp index 8de081b76e..d27715350b 100644 --- a/tests/unittests/phy/upper/channel_processors/pdsch_processor_vectortest.cpp +++ b/tests/unittests/phy/upper/channel_processors/pdsch_processor_vectortest.cpp @@ -219,7 +219,7 @@ class PdschProcessorFixture : public ::testing::TestWithParam Date: Tue, 5 Mar 2024 11:52:44 +0100 Subject: [PATCH 088/140] adt: fix noexcept for intrusive_ptr --- include/srsran/adt/detail/intrusive_ptr.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/srsran/adt/detail/intrusive_ptr.h b/include/srsran/adt/detail/intrusive_ptr.h index 8722da5003..136d2de632 100644 --- a/include/srsran/adt/detail/intrusive_ptr.h +++ b/include/srsran/adt/detail/intrusive_ptr.h @@ -45,7 +45,7 @@ class intrusive_ptr } } - intrusive_ptr(const intrusive_ptr& other) : ptr(other.ptr) + intrusive_ptr(const intrusive_ptr& other) noexcept : ptr(other.ptr) { if (ptr != nullptr) { intrusive_ptr_inc_ref(ptr); @@ -61,7 +61,7 @@ class intrusive_ptr } } - intrusive_ptr& operator=(intrusive_ptr& other) + intrusive_ptr& operator=(intrusive_ptr& other) noexcept { if (ptr != other.ptr) { T* temp = ptr; From e79dcadfc1075a3cfbef096217efe65ed479e7e6 Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Tue, 5 Mar 2024 15:16:58 +0100 Subject: [PATCH 089/140] ntn: parse epoch_time config parameters --- apps/gnb/gnb_appconfig_cli11_schema.cpp | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/apps/gnb/gnb_appconfig_cli11_schema.cpp b/apps/gnb/gnb_appconfig_cli11_schema.cpp index 95cbdffeb5..13d18a2e51 100644 --- a/apps/gnb/gnb_appconfig_cli11_schema.cpp +++ b/apps/gnb/gnb_appconfig_cli11_schema.cpp @@ -961,6 +961,14 @@ static void configure_cli11_si_sched_info(CLI::App& app, sib_appconfig::si_sched ->check(CLI::IsMember({2, 19})); } +static void configure_cli11_epoch_time(CLI::App& app, epoch_time_t& epoch_time) +{ + app.add_option("--sfn", epoch_time.sfn, "SFN Part")->capture_default_str()->check(CLI::Range(0, 1023)); + app.add_option("--subframe_number", epoch_time.subframe_number, "Sub-frame number Part") + ->capture_default_str() + ->check(CLI::Range(0, 9)); +} + static void configure_cli11_ephemeris_info_ecef(CLI::App& app, ecef_coordinates_t& ephemeris_info) { app.add_option("--pos_x", ephemeris_info.position_x, "X Position of the satellite") @@ -997,6 +1005,7 @@ static void configure_cli11_ephemeris_info_orbital(CLI::App& app, orbital_coordi } static void configure_cli11_ntn_args(CLI::App& app, optional& ntn, + epoch_time_t& epoch_time, orbital_coordinates_t& orbital_coordinates, ecef_coordinates_t& ecef_coordinates) { @@ -1008,6 +1017,10 @@ static void configure_cli11_ntn_args(CLI::App& app, ntn.value().ta_info.emplace(); app.add_option("--ta_common", ntn->ta_info->ta_common, "TA common offset"); + // epoch time. + CLI::App* epoch_time_subcmd = app.add_subcommand("epoch_time", "Epoch time for the NTN assistance information"); + configure_cli11_epoch_time(*epoch_time_subcmd, epoch_time); + // ephemeris configuration. CLI::App* ephem_subcmd_ecef = app.add_subcommand("ephemeris_info_ecef", "ephermeris information of the satellite in ecef coordinates"); @@ -2298,13 +2311,19 @@ static void manage_hal_optional(CLI::App& app, gnb_appconfig& gnb_cfg) static void manage_ntn_optional(CLI::App& app, gnb_appconfig& gnb_cfg, + epoch_time_t& epoch_time, orbital_coordinates_t orbital_coordinates, ecef_coordinates_t ecef_coordinates) { auto ntn_app = app.get_subcommand_ptr("ntn"); + unsigned nof_epoch_entries = ntn_app->get_subcommand("epoch_time")->count_all(); unsigned nof_ecef_entries = ntn_app->get_subcommand("ephemeris_info_ecef")->count_all(); unsigned nof_orbital_entries = ntn_app->get_subcommand("ephemeris_orbital")->count_all(); + if (nof_epoch_entries) { + gnb_cfg.ntn_cfg.value().epoch_time = epoch_time; + } + if (nof_ecef_entries) { gnb_cfg.ntn_cfg.value().ephemeris_info = ecef_coordinates; } else if (nof_orbital_entries) { @@ -2413,9 +2432,10 @@ void srsran::configure_cli11_with_gnb_appconfig_schema(CLI::App& app, gnb_parsed // NTN section. CLI::App* ntn_subcmd = app.add_subcommand("ntn", "NTN parameters")->configurable(); + static epoch_time_t epoch_time; static ecef_coordinates_t ecef_coordinates; static orbital_coordinates_t orbital_coordinates; - configure_cli11_ntn_args(*ntn_subcmd, gnb_cfg.ntn_cfg, orbital_coordinates, ecef_coordinates); + configure_cli11_ntn_args(*ntn_subcmd, gnb_cfg.ntn_cfg, epoch_time, orbital_coordinates, ecef_coordinates); // NOTE: CLI11 needs that the life of the variable lasts longer than the call of this function. As both options need // to be added and a variant is used to store the Radio Unit configuration, the configuration is parsed in a helper @@ -2549,7 +2569,7 @@ void srsran::configure_cli11_with_gnb_appconfig_schema(CLI::App& app, gnb_parsed app.callback([&]() { manage_ru_variant(app, gnb_cfg, sdr_cfg, ofh_cfg, dummy_cfg); manage_hal_optional(app, gnb_cfg); - manage_ntn_optional(app, gnb_cfg, orbital_coordinates, ecef_coordinates); + manage_ntn_optional(app, gnb_cfg, epoch_time, orbital_coordinates, ecef_coordinates); manage_processing_delay(app, gnb_cfg); manage_expert_execution_threads(app, gnb_cfg); }); From 51f2b73bef166d260308f884825f1542d366333f Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Tue, 5 Mar 2024 15:17:29 +0100 Subject: [PATCH 090/140] ntn: fix sib19 parameters scaling --- apps/gnb/gnb_appconfig_translators.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/gnb/gnb_appconfig_translators.cpp b/apps/gnb/gnb_appconfig_translators.cpp index 5ac36411c0..7377ef635b 100644 --- a/apps/gnb/gnb_appconfig_translators.cpp +++ b/apps/gnb/gnb_appconfig_translators.cpp @@ -432,7 +432,11 @@ static sib19_info create_sib19_info(const gnb_appconfig& config) variant_get(sib19.ephemeris_info.value()).position_x /= 1.3; variant_get(sib19.ephemeris_info.value()).position_y /= 1.3; variant_get(sib19.ephemeris_info.value()).position_z /= 1.3; + variant_get(sib19.ephemeris_info.value()).velocity_vx /= 0.06; + variant_get(sib19.ephemeris_info.value()).velocity_vy /= 0.06; + variant_get(sib19.ephemeris_info.value()).velocity_vz /= 0.06; } else if (variant_holds_alternative(sib19.ephemeris_info.value())) { + variant_get(sib19.ephemeris_info.value()).semi_major_axis -= 6500000; variant_get(sib19.ephemeris_info.value()).semi_major_axis /= 0.004249; variant_get(sib19.ephemeris_info.value()).eccentricity /= 0.00000001431; variant_get(sib19.ephemeris_info.value()).periapsis /= 0.00000002341; From cb0e4df5a829da7f31535514f6ce7d5a8a3f4b9b Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Tue, 5 Mar 2024 14:21:04 +0100 Subject: [PATCH 091/140] sched: filter out only monitored SearchSpaces --- lib/scheduler/ue_scheduling/ue_cell.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_cell.cpp b/lib/scheduler/ue_scheduling/ue_cell.cpp index b83149fc51..fa4c760d63 100644 --- a/lib/scheduler/ue_scheduling/ue_cell.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell.cpp @@ -253,7 +253,9 @@ ue_cell::get_active_dl_search_spaces(slot_point pdcch_slo "Invalid required dci-rnti parameter"); for (const search_space_configuration& ss : ue_cfg->cell_cfg_common.dl_cfg_common.init_dl_bwp.pdcch_common.search_spaces) { - active_search_spaces.push_back(&ue_cfg->search_space(ss.get_id())); + if (pdcch_helper::is_pdcch_monitoring_active(pdcch_slot, ss)) { + active_search_spaces.push_back(&ue_cfg->search_space(ss.get_id())); + } } return active_search_spaces; } @@ -293,6 +295,10 @@ ue_cell::get_active_dl_search_spaces(slot_point pdcch_slo } } + if (not pdcch_helper::is_pdcch_monitoring_active(pdcch_slot, *ss.cfg)) { + return false; + } + if (ss.get_pdcch_candidates(get_aggregation_level(channel_state_manager().get_wideband_cqi(), ss, true), pdcch_slot) .empty()) { return false; @@ -318,7 +324,9 @@ ue_cell::get_active_ul_search_spaces(slot_point pdcch_slo "Invalid required dci-rnti parameter"); for (const search_space_configuration& ss : ue_cfg->cell_cfg_common.dl_cfg_common.init_dl_bwp.pdcch_common.search_spaces) { - active_search_spaces.push_back(&ue_cfg->search_space(ss.get_id())); + if (pdcch_helper::is_pdcch_monitoring_active(pdcch_slot, ss)) { + active_search_spaces.push_back(&ue_cfg->search_space(ss.get_id())); + } } return active_search_spaces; } @@ -358,6 +366,10 @@ ue_cell::get_active_ul_search_spaces(slot_point pdcch_slo } } + if (not pdcch_helper::is_pdcch_monitoring_active(pdcch_slot, *ss.cfg)) { + return false; + } + if (ss.get_pdcch_candidates(get_aggregation_level(channel_state_manager().get_wideband_cqi(), ss, false), pdcch_slot) .empty()) { From c9a64d2fe090be10a0be4618c12e3d03366fe3b5 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Tue, 5 Mar 2024 14:54:13 +0100 Subject: [PATCH 092/140] unittest: add test to verify only monitored common SearchSpaces are used during fallback --- .../scheduler_ue_fallback_mode_test.cpp | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/unittests/scheduler/scheduler_ue_fallback_mode_test.cpp b/tests/unittests/scheduler/scheduler_ue_fallback_mode_test.cpp index 62e372ca09..67c6e0eb14 100644 --- a/tests/unittests/scheduler/scheduler_ue_fallback_mode_test.cpp +++ b/tests/unittests/scheduler/scheduler_ue_fallback_mode_test.cpp @@ -214,6 +214,34 @@ TEST_P(scheduler_con_res_msg4_test, while_ue_is_in_fallback_then_common_pucch_is ASSERT_FALSE(pucch_ptr->resources.second_hop_prbs.empty()) << "For common PUCCH resources, second hop is used"; } +TEST_P(scheduler_con_res_msg4_test, while_ue_is_in_fallback_then_common_ss_is_used) +{ + const static unsigned msg4_size = 128; + + // Enqueue ConRes CE + Msg4. + this->sched->handle_dl_mac_ce_indication(dl_mac_ce_indication{ue_index, lcid_dl_sch_t::UE_CON_RES_ID}); + this->push_dl_buffer_state(dl_buffer_state_indication_message{this->ue_index, params.msg4_lcid, msg4_size}); + + // Wait for ConRes + Msg4 PDCCH to be scheduled. + ASSERT_TRUE(this->run_slot_until([this]() { return find_ue_dl_pdcch(rnti) != nullptr; })); + + const pdcch_dl_information& dl_pdcch = *find_ue_dl_pdcch(rnti); + bool is_common_ss_used = false; + const search_space_configuration* ss_used = nullptr; + for (const search_space_configuration& ss : + cell_cfg_list.front().dl_cfg_common.init_dl_bwp.pdcch_common.search_spaces) { + if (dl_pdcch.ctx.context.ss_id == ss.get_id()) { + is_common_ss_used = true; + ss_used = &ss; + break; + } + } + ASSERT_TRUE(is_common_ss_used) << "UE in fallback should use common SS"; + // PDCCH monitoring must be active in this slot. + ASSERT_TRUE(ss_used != nullptr and pdcch_helper::is_pdcch_monitoring_active(next_slot, *ss_used)) + << fmt::format("Common SS id={} is not monitored at slot={}", ss_used->get_id(), next_slot.slot_index()); +} + INSTANTIATE_TEST_SUITE_P(scheduler_con_res_msg4_test, scheduler_con_res_msg4_test, ::testing::Values(conres_test_params{LCID_SRB0, duplex_mode::FDD}, From a39eeb7ee35f9f56072a4ec61162b932450c4ad8 Mon Sep 17 00:00:00 2001 From: asaezper Date: Tue, 5 Mar 2024 13:38:42 +0100 Subject: [PATCH 093/140] ci: upgrade amari version --- .gitlab/ci/e2e/.env | 4 ++-- .gitlab/ci/trx.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index 2da4828430..e680b1f35a 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -1,7 +1,7 @@ SRSGNB_REGISTRY_URI=registry.gitlab.com/softwareradiosystems/srsgnb RETINA_REGISTRY_PREFIX=registry.gitlab.com/softwareradiosystems/ci/retina -RETINA_VERSION=0.43.4 -AMARISOFT_VERSION=2023-03-17 +RETINA_VERSION=0.44.0 +AMARISOFT_VERSION=2024-02-20 SRSUE_VERSION=23.11 OPEN5GS_VERSION=2.6.1 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin diff --git a/.gitlab/ci/trx.yml b/.gitlab/ci/trx.yml index 5fe4d53036..536d9bc824 100644 --- a/.gitlab/ci/trx.yml +++ b/.gitlab/ci/trx.yml @@ -19,7 +19,7 @@ build trx driver: extends: .build_and_unit variables: AMARISOFT_PACKAGE_REGISTRY: ${CI_API_V4_URL}/projects/44296988/packages/generic/amarisoft - AMARISOFT_VERSION: "2023-03-17" + AMARISOFT_VERSION: "2024-02-20" KUBERNETES_CPU_REQUEST: 2 KUBERNETES_CPU_LIMIT: 2 KUBERNETES_MEMORY_REQUEST: 2.5Gi From faab126d6abb7e8fe6234d514465d1eab5d3e677 Mon Sep 17 00:00:00 2001 From: Pavel Harbanau Date: Tue, 5 Mar 2024 20:41:04 +0000 Subject: [PATCH 094/140] gnb: discover CPU architecture --- CMakeLists.txt | 9 + apps/gnb/gnb.cpp | 3 + apps/gnb/gnb_appconfig.h | 3 +- cmake/modules/FindNUMA.cmake | 28 ++ .../srsran/support/cpu_architecture_info.h | 82 ++++++ include/srsran/support/unique_thread.h | 15 +- lib/support/CMakeLists.txt | 6 +- lib/support/cpu_architecture_info.cpp | 263 ++++++++++++++++++ lib/support/unique_thread.cpp | 62 +---- 9 files changed, 400 insertions(+), 71 deletions(-) create mode 100644 cmake/modules/FindNUMA.cmake create mode 100644 include/srsran/support/cpu_architecture_info.h create mode 100644 lib/support/cpu_architecture_info.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 39eff94b38..d691428c85 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,7 @@ option(ENABLE_UHD "Enable UHD" ON) option(ENABLE_ZEROMQ "Enable ZeroMQ" ON) option(ENABLE_FFTW "Enable FFTW" ON) option(ENABLE_DPDK "Enable DPDK" OFF) +option(ENABLE_LIBNUMA "Enable LibNUMA" OFF) option(ENABLE_EXPORT "Enable PIC and export libraries" OFF) option(ENABLE_TRX_DRIVER "Enable Amarisoft TRX driver library" OFF) option(AUTO_DETECT_ISA "Enable automatic ISA detection" ON) @@ -251,6 +252,14 @@ else (ENABLE_ZEROMQ) unset(ZEROMQ_FOUND CACHE) endif (ENABLE_ZEROMQ) +if (ENABLE_LIBNUMA) + find_package(NUMA) + if (NUMA_FOUND) + include_directories(${NUMA_INCLUDE_DIRS}) + add_definitions(-DNUMA_SUPPORT) + endif (NUMA_FOUND) +endif (ENABLE_LIBNUMA) + # DPDK if (ENABLE_DPDK) set(DPDK_MIN_VERSION "22.11") diff --git a/apps/gnb/gnb.cpp b/apps/gnb/gnb.cpp index fe1ad58a8c..23c3c48026 100644 --- a/apps/gnb/gnb.cpp +++ b/apps/gnb/gnb.cpp @@ -321,6 +321,9 @@ int main(int argc, char** argv) // Log build info gnb_logger.info("Built in {} mode using {}", get_build_mode(), get_build_info()); + // Log CPU architecture. + cpu_architecture_info::get().print_cpu_info(gnb_logger); + // Check and log included CPU features and check support by current CPU if (cpu_supports_included_features()) { gnb_logger.debug("Required CPU features: {}", get_cpu_feature_info()); diff --git a/apps/gnb/gnb_appconfig.h b/apps/gnb/gnb_appconfig.h index bfad124701..7252ab01e1 100644 --- a/apps/gnb/gnb_appconfig.h +++ b/apps/gnb/gnb_appconfig.h @@ -32,6 +32,7 @@ #include "srsran/ran/sib/system_info_config.h" #include "srsran/ran/slot_pdu_capacity_constants.h" #include "srsran/ran/subcarrier_spacing.h" +#include "srsran/support/cpu_architecture_info.h" #include "srsran/support/unique_thread.h" #include "srsran/support/units.h" #include @@ -1147,7 +1148,7 @@ struct ofh_threads_appconfig { struct expert_threads_appconfig { expert_threads_appconfig() { - unsigned nof_threads = compute_host_nof_hardware_threads(); + unsigned nof_threads = cpu_architecture_info::get().get_host_nof_available_cpus(); if (nof_threads < 4) { upper_threads.nof_ul_threads = 1; diff --git a/cmake/modules/FindNUMA.cmake b/cmake/modules/FindNUMA.cmake new file mode 100644 index 0000000000..61b240ee79 --- /dev/null +++ b/cmake/modules/FindNUMA.cmake @@ -0,0 +1,28 @@ +# +# Copyright 2021-2023 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. +# + +find_package(PkgConfig REQUIRED) + +find_path( + NUMA_INCLUDE_DIRS + NAMES numa.h numaif.h + PATHS /usr/local/include + /usr/include +) + +find_library( + NUMA_LIBRARIES + NAMES numa + PATHS /usr/local/lib + /usr/lib + /usr/lib/x86_64-linux-gnu +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(NUMA DEFAULT_MSG NUMA_LIBRARIES NUMA_INCLUDE_DIRS) +MARK_AS_ADVANCED(NUMA_LIBRARIES NUMA_INCLUDE_DIRS) diff --git a/include/srsran/support/cpu_architecture_info.h b/include/srsran/support/cpu_architecture_info.h new file mode 100644 index 0000000000..9efe520263 --- /dev/null +++ b/include/srsran/support/cpu_architecture_info.h @@ -0,0 +1,82 @@ +/* + * + * Copyright 2021-2023 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/bounded_bitset.h" + +namespace srsran { + +/// Class discovering the CPU architecture of the underlying hardware. +class cpu_architecture_info +{ + /// Aggregates CPU information. + struct cpu_description { + /// Set of CPUs as returned by the OS. + cpu_set_t cpuset; + /// Total number of CPUs. + size_t nof_cpus; + /// Number of available CPUs. + size_t nof_available_cpus; + /// Highest index of the available CPU. + size_t max_cpu_id; + /// List of CPUs that the application is allowed to use. + bounded_bitset<1024> allowed_cpus; + /// Number of NUMA nodes. + size_t nof_numa_nodes; + /// List of CPUs pertaining to each NUMA node. + std::vector> node_cpus; + /// Lists of logical CPUs belonging to each physical CPU. + std::vector> logical_cpu_lists; + }; + + /// Discovers CPU architecture at the application start-up. + static cpu_description discover_cpu_architecture(); + + /// Stores the CPU description. + static const cpu_description cpu_desc; + + /// Default constructor. + cpu_architecture_info() = default; + +public: + cpu_architecture_info(const cpu_architecture_info& other) = delete; + cpu_architecture_info(cpu_architecture_info&& other) = delete; + void operator=(const cpu_architecture_info& other) = delete; + void operator=(cpu_architecture_info&& other) = delete; + + /// Returns reference to a static instance of this class. + static cpu_architecture_info& get() + { + /// Singleton object. + static cpu_architecture_info cpu_info; + return cpu_info; + } + + /// Get total number of CPUs discovered in the given host. + size_t get_host_total_nof_cpus() const { return cpu_desc.nof_cpus; } + + /// Get the number of CPUs available to the application. + size_t get_host_nof_available_cpus() const { return cpu_desc.nof_available_cpus; } + + /// Get available CPUs as a cpu_set_t structure. + cpu_set_t get_available_cpuset() const { return cpu_desc.cpuset; } + + /// Prints discovered CPU information. + void print_cpu_info(srslog::basic_logger& logger) const; + + /// Returns CPUs of the given NUMA node. + bounded_bitset<1024> get_node_cpu_mask(unsigned node_id) const; + + /// Run calling thread and its children and allocate memory on the given NUMA node. + bool run_on_numa_node(unsigned node_id) const; +}; + +} // namespace srsran diff --git a/include/srsran/support/unique_thread.h b/include/srsran/support/unique_thread.h index 52fe48afb6..7f058357de 100644 --- a/include/srsran/support/unique_thread.h +++ b/include/srsran/support/unique_thread.h @@ -10,6 +10,7 @@ #pragma once +#include "cpu_architecture_info.h" #include "srsran/adt/bounded_bitset.h" #include "srsran/adt/strong_type.h" #include "srsran/adt/unique_function.h" @@ -18,12 +19,6 @@ namespace srsran { -/// Computes the number of threads that are usable in the given host. -size_t compute_host_nof_hardware_threads(); - -/// Get maximum CPU ID available to the application. -size_t get_host_max_cpu_id(); - /// OS thread RT scheduling priority. /// Note: posix defines a minimum spread between sched_get_priority_max() and sched_get_priority_min() of 32. struct os_thread_realtime_priority_tag {}; @@ -100,9 +95,13 @@ struct os_sched_affinity_bitmask { public: static constexpr size_t MAX_CPUS = 1024; - os_sched_affinity_bitmask() : cpu_bitset(get_host_max_cpu_id() + 1) {} + os_sched_affinity_bitmask() : cpu_bitset(cpu_architecture_info::get().get_host_total_nof_cpus()) {} - explicit os_sched_affinity_bitmask(size_t cpu_idx) : cpu_bitset(get_host_max_cpu_id() + 1) { set(cpu_idx); } + explicit os_sched_affinity_bitmask(size_t cpu_idx) : + cpu_bitset(cpu_architecture_info::get().get_host_total_nof_cpus()) + { + set(cpu_idx); + } os_sched_affinity_bitmask(size_t bitset_size, size_t cpu_idx) : cpu_bitset(bitset_size) { set(cpu_idx); } diff --git a/lib/support/CMakeLists.txt b/lib/support/CMakeLists.txt index 3b32c68031..fe6fd48505 100644 --- a/lib/support/CMakeLists.txt +++ b/lib/support/CMakeLists.txt @@ -24,10 +24,12 @@ set(SOURCES event_tracing.cpp sysinfo.cpp byte_buffer.cpp - byte_buffer_chain.cpp) + byte_buffer_chain.cpp + cpu_architecture_info.cpp) add_library(srsran_support STATIC ${SOURCES}) -target_link_libraries(srsran_support srsran_network ${CMAKE_THREAD_LIBS_INIT} ${YAMLCPP_LIBRARY} srslog) +target_link_libraries(srsran_support srsran_network ${CMAKE_THREAD_LIBS_INIT} ${YAMLCPP_LIBRARY} + ${NUMA_LIBRARIES} srslog) add_backward(srsran_support) if (Backward_FOUND AND BACKWARD_HAS_EXTERNAL_LIBRARIES) diff --git a/lib/support/cpu_architecture_info.cpp b/lib/support/cpu_architecture_info.cpp new file mode 100644 index 0000000000..214dffcf68 --- /dev/null +++ b/lib/support/cpu_architecture_info.cpp @@ -0,0 +1,263 @@ +/* + * + * Copyright 2021-2023 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/support/cpu_architecture_info.h" +#include "srsran/adt/interval.h" +#include "srsran/support/format_utils.h" +#include "srsran/support/sysinfo.h" +#include +#include +#include +#include +#include +#include +#ifdef NUMA_SUPPORT +#include +#endif + +using namespace srsran; + +/// Converts the string containing a CPU index to an unsigned integer number. +static unsigned parse_one_cpu(const std::string& value) +{ + return std::stoi(value); +} + +/// Parses string representing range of CPU indexes in the format 'M-N'. +static interval parse_cpu_range(const std::string& value) +{ + std::vector range; + std::stringstream ss(value); + + while (ss.good()) { + std::string str; + std::getline(ss, str, '-'); + auto parse_result = parse_one_cpu(str); + range.push_back(parse_result); + } + return interval(range[0], range[1]); +} + +// Obtain CPU description at the start of the application. This value is affected by commands or tools like taskset, +// which limit the number of cores available to the application. However, frameworks (e.g. DPDK) that affect the +// affinities of the main thread in the main() function will not affect this value. +const cpu_architecture_info::cpu_description cpu_architecture_info::cpu_desc = + cpu_architecture_info::discover_cpu_architecture(); + +cpu_architecture_info::cpu_description cpu_architecture_info::discover_cpu_architecture() +{ + // Clean-up cgroups possibly left from a previous run. + cleanup_cgroups(); + + cpu_description cpuinfo; + cpu_set_t& cpuset = cpuinfo.cpuset; + + // Discover host CPU architecture. + CPU_ZERO(&cpuset); + cpuinfo.allowed_cpus.resize(CPU_SETSIZE); + + if (::sched_getaffinity(0, sizeof(cpuset), &cpuset) == 0) { + cpuinfo.nof_available_cpus = CPU_COUNT(&cpuset); + // Save bitmask of CPUs the calling thread is allowed to run on. + for (unsigned i = 0; i != CPU_SETSIZE; ++i) { + if (CPU_ISSET(i, &cpuset)) { + cpuinfo.allowed_cpus.set(i); + } + } + } else { + // Parse /proc/self/status + std::ifstream file("/proc/self/status"); + std::string line; + while (std::getline(file, line)) { + // Look for allowed CPUs mask in hexadecimal format. + if (line.find("Cpus_allowed_list") != std::string::npos) { + const std::regex re("([0-9]+)(.*)$"); + std::smatch m; + std::regex_search(line, m, re); + std::istringstream iss(line.substr(m.position())); + while (iss.good()) { + std::string str; + std::getline(iss, str, ','); + if (str.find('-') != std::string::npos) { + auto range = parse_cpu_range(str); + cpuinfo.allowed_cpus.fill(range.start(), range.stop() + 1); + } else { + auto cpu_idx = parse_one_cpu(str); + cpuinfo.allowed_cpus.set(cpu_idx); + } + } + break; + } + } + } + cpuinfo.nof_available_cpus = cpuinfo.allowed_cpus.count(); + cpuinfo.max_cpu_id = cpuinfo.allowed_cpus.find_highest(); + cpuinfo.nof_cpus = cpuinfo.max_cpu_id + 1; + cpuinfo.allowed_cpus.resize(cpuinfo.nof_cpus); + + // Parse /sys/devices/system/cpu/cpu*/topology/thread_siblings_list to get the lists of logical cores belonging to + // the same physical core. + std::set thread_siblings_set; + std::string cpu_system_path = "/sys/devices/system/cpu"; + ::DIR* dir = ::opendir(cpu_system_path.c_str()); + if (dir) { + ::dirent* entry; + struct ::stat info; + + while ((entry = ::readdir(dir))) { + const std::regex re("^cpu[0-9]+"); + std::string cpu_name = entry->d_name; + if (!std::regex_match(cpu_name, re)) { + continue; + } + std::string cpu_siblings_path = fmt::format("{}/{}/topology/thread_siblings_list", cpu_system_path, cpu_name); + if (::stat(cpu_siblings_path.c_str(), &info) < 0) { + continue; + } + std::ifstream file(cpu_siblings_path); + std::string str_mask; + std::getline(file, str_mask); + thread_siblings_set.insert(str_mask); + } + ::closedir(dir); + } + for (const auto& mask : thread_siblings_set) { + cpuinfo.logical_cpu_lists.emplace_back(); + auto& bitmask = cpuinfo.logical_cpu_lists.back(); + bitmask.resize(cpuinfo.nof_cpus); + + std::istringstream iss(mask); + while (iss.good()) { + std::string str; + std::getline(iss, str, ','); + if (str.find('-') != std::string::npos) { + auto range = parse_cpu_range(str); + bitmask.fill(range.start(), range.stop() + 1); + } else { + auto cpu_idx = parse_one_cpu(str); + bitmask.set(cpu_idx); + } + } + } + +#ifdef NUMA_SUPPORT + if (::numa_available() == -1) { + return cpuinfo; + } + cpuinfo.nof_cpus = ::numa_num_configured_cpus(); + cpuinfo.nof_available_cpus = ::numa_num_task_cpus(); + cpuinfo.nof_numa_nodes = ::numa_num_configured_nodes(); + + // Save bitmasks of the CPUs pertaining to each NUMA node. + for (unsigned node = 0; node != cpuinfo.nof_numa_nodes; ++node) { + ::bitmask* mask = ::numa_allocate_cpumask(); + ::numa_node_to_cpus(node, mask); + + cpuinfo.node_cpus.emplace_back(numa_num_configured_cpus()); + cpuinfo.node_cpus[node].from_uint64(*mask->maskp); + ::numa_free_cpumask(mask); + } +#else + std::string node_system_path = "/sys/devices/system/node"; + dir = ::opendir(node_system_path.c_str()); + if (dir) { + ::dirent* entry; + while ((entry = ::readdir(dir))) { + const std::regex re("^node[0-9]+"); + std::string entry_name = entry->d_name; + if (std::regex_match(entry_name, re)) { + ++cpuinfo.nof_numa_nodes; + } + } + ::closedir(dir); + } +#endif // NUMA_SUPPORT + + return cpuinfo; +} + +static std::string print_cpus_list(const bounded_bitset<1024>& cpus_mask) +{ + auto cpu_ids = cpus_mask.get_bit_positions(); + if (cpu_ids.empty()) { + return "[]"; + } + fmt::memory_buffer fmt_format_buf; + fmt::format_to(fmt_format_buf, "["); + for (unsigned idx = 0, e = cpu_ids.size(); idx != e; ++idx) { + fmt::format_to(fmt_format_buf, "{}{}", cpu_ids[idx], (idx == cpu_ids.size() - 1) ? "]" : ","); + } + return to_string(fmt_format_buf); +} + +void cpu_architecture_info::print_cpu_info(srslog::basic_logger& logger) const +{ + fmt::memory_buffer fmt_buf; + fmt::format_to(fmt_buf, + "{} {}, {} NUMA {}.\n", + cpu_desc.nof_cpus, + (cpu_desc.nof_cpus > 1) ? "CPUs" : "CPU", + cpu_desc.nof_numa_nodes, + cpu_desc.nof_numa_nodes > 1 ? "nodes" : "node"); + +#ifdef NUMA_SUPPORT + fmt::format_to(fmt_buf, "CPUs per NUMA node:\n{{"); + for (unsigned node = 0; node != cpu_desc.nof_numa_nodes; ++node) { + fmt::format_to(fmt_buf, "\n Node {} CPUs: {}", node, print_cpus_list(cpu_desc.node_cpus[node])); + } + fmt::format_to(fmt_buf, "\n}}\n"); +#endif + + fmt::format_to(fmt_buf, "CPUs per each physical CPU core:\n{{"); + for (unsigned core_id = 0, e = cpu_desc.logical_cpu_lists.size(); core_id != e; ++core_id) { + fmt::format_to(fmt_buf, "\n {}: {}", core_id, print_cpus_list(cpu_desc.logical_cpu_lists[core_id])); + } + fmt::format_to(fmt_buf, "\n}}\n"); + fmt::format_to(fmt_buf, + "{} CPUs available to the application: {}", + cpu_desc.nof_available_cpus, + print_cpus_list(cpu_desc.allowed_cpus)); + + logger.debug("Detected CPU topology: {}", to_c_str(fmt_buf)); +} + +bounded_bitset<1024> cpu_architecture_info::get_node_cpu_mask(unsigned node_id) const +{ +#ifndef NUMA_SUPPORT + srslog::fetch_basic_logger("GNB").debug("NUMA topology not available, please compile the code with libnuma support"); + return {}; +#else + + if (node_id >= cpu_desc.nof_numa_nodes) { + srslog::fetch_basic_logger("GNB").debug("Requested node ID exceeds number of NUMA nodes configured in the system"); + return {}; + } + return cpu_desc.node_cpus[node_id]; +#endif +} + +bool cpu_architecture_info::run_on_numa_node(unsigned node_id) const +{ +#ifndef NUMA_SUPPORT + srslog::fetch_basic_logger("GNB").debug("NUMA topology not available, please compile the code with libnuma support"); + return false; +#else + + if (node_id >= cpu_desc.nof_numa_nodes) { + srslog::fetch_basic_logger("GNB").debug("Requested node ID exceeds number of NUMA nodes configured in the system"); + return false; + } + ::bitmask* mask = ::numa_allocate_nodemask(); + ::numa_bitmask_setbit(mask, node_id); + ::numa_bind(mask); + ::numa_free_nodemask(mask); + return true; +#endif +} diff --git a/lib/support/unique_thread.cpp b/lib/support/unique_thread.cpp index ebf2858617..14f1beec2a 100644 --- a/lib/support/unique_thread.cpp +++ b/lib/support/unique_thread.cpp @@ -9,7 +9,6 @@ */ #include "srsran/support/unique_thread.h" -#include "srsran/support/sysinfo.h" #include "fmt/ostream.h" #include #include @@ -17,64 +16,6 @@ using namespace srsran; -namespace { - -struct cpu_description { - cpu_set_t cpuset; - size_t nof_cores; - size_t max_cpu_id; -}; - -/// \brief Compute the CPU set of the caller thread. -cpu_description compute_machine_desc() -{ - // Clean-up cgroups possibly left from a previous run. - cleanup_cgroups(); - - cpu_description desc; - cpu_set_t& cpuset = desc.cpuset; - - // Compute the CPU bitmask. - CPU_ZERO(&cpuset); - if (sched_getaffinity(0, sizeof(cpuset), &cpuset) != 0) { - printf("Warning: Could not get CPU affinity of main thread. Cause: %s\n", strerror(errno)); - // In failure case, we set all CPUs as available. - unsigned nof_cores = std::max(1U, std::thread::hardware_concurrency()); - for (size_t i = 0; i < nof_cores; ++i) { - CPU_SET(i, &cpuset); - } - } - - // Compute the number of cores. - desc.nof_cores = std::max(1, CPU_COUNT(&cpuset)); - - // Compute max CPU id. - for (unsigned i = 0; i < CPU_SETSIZE; ++i) { - if (CPU_ISSET(i, &cpuset)) { - desc.max_cpu_id = i; - } - } - - return desc; -} - -// Obtain CPU description at the start of the application. This value is affected by commands or tools like taskset, -// which limit the number of cores available to the application. However, frameworks (e.g. DPDK) that affect the -// affinities of the main thread in the main() function will not affect this value. -const cpu_description host_desc = compute_machine_desc(); - -} // namespace - -size_t srsran::compute_host_nof_hardware_threads() -{ - return host_desc.nof_cores; -} - -size_t srsran::get_host_max_cpu_id() -{ - return host_desc.max_cpu_id; -} - /// Sets thread OS scheduling real-time priority. static bool thread_set_param(pthread_t t, os_thread_realtime_priority prio) { @@ -178,8 +119,9 @@ const os_sched_affinity_bitmask& os_sched_affinity_bitmask::available_cpus() { static os_sched_affinity_bitmask available_cpus_mask = []() { os_sched_affinity_bitmask bitmask; + cpu_set_t cpuset = cpu_architecture_info::get().get_available_cpuset(); for (size_t i = 0; i < bitmask.size(); ++i) { - if (CPU_ISSET(i, &host_desc.cpuset)) { + if (CPU_ISSET(i, &cpuset)) { bitmask.cpu_bitset.set(i); } } From 9bd57d26584614191904f862d913d8fb4c89420d Mon Sep 17 00:00:00 2001 From: asaezper Date: Wed, 6 Mar 2024 16:22:09 +0100 Subject: [PATCH 095/140] ci,e2e: test mode parameters --- tests/e2e/tests/test_mode.py | 14 +++++++------- tests/e2e/tests/test_mode/config_ue.yml | 6 ++++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/tests/e2e/tests/test_mode.py b/tests/e2e/tests/test_mode.py index b427e789f1..91aea14221 100644 --- a/tests/e2e/tests/test_mode.py +++ b/tests/e2e/tests/test_mode.py @@ -31,13 +31,13 @@ @mark.parametrize( "extra_config, nof_ant", ( - param("test_mode test_ue --rnti 0x44 --cqi 15 --ri 1", 1, id="Test UE 1x1 Rank 1"), - param("test_mode test_ue --rnti 0x44 --cqi 15 --ri 1", 2, id="Test UE 2x2 Rank 1"), - param("test_mode test_ue --rnti 0x44 --cqi 15 --ri 2", 2, id="Test UE 2x2 Rank 2"), - param("test_mode test_ue --rnti 0x44 --cqi 15 --ri 1", 4, id="Test UE 4x4 Rank 1"), - param("test_mode test_ue --rnti 0x44 --cqi 15 --ri 2", 4, id="Test UE 4x4 Rank 2"), - param("test_mode test_ue --rnti 0x44 --cqi 15 --ri 3", 4, id="Test UE 4x4 Rank 3"), - param("test_mode test_ue --rnti 0x44 --cqi 15 --ri 4", 4, id="Test UE 4x4 Rank 4"), + param("test_mode test_ue --ri 1", 1, id="Test UE 1x1 Rank 1"), + param("test_mode test_ue --ri 1", 2, id="Test UE 2x2 Rank 1"), + param("test_mode test_ue --ri 2", 2, id="Test UE 2x2 Rank 2"), + param("test_mode test_ue --ri 1", 4, id="Test UE 4x4 Rank 1"), + param("test_mode test_ue --ri 2", 4, id="Test UE 4x4 Rank 2"), + param("test_mode test_ue --ri 3", 4, id="Test UE 4x4 Rank 3"), + param("test_mode test_ue --ri 4", 4, id="Test UE 4x4 Rank 4"), ), ) @mark.test_mode diff --git a/tests/e2e/tests/test_mode/config_ue.yml b/tests/e2e/tests/test_mode/config_ue.yml index 3da5fb9530..694cfdd3bd 100644 --- a/tests/e2e/tests/test_mode/config_ue.yml +++ b/tests/e2e/tests/test_mode/config_ue.yml @@ -49,10 +49,12 @@ cell_cfg: nof_dl_symbols: 7 nof_dl_slots: 7 nof_ul_slots: 2 + # nof_antennas_dl: 1 - Set in gnb call. Please check it in agent.log + # nof_antennas_ul: 1 - Set in gnb call. Please check it in agent.log test_mode: test_ue: - rnti: 0x4655 - ri: 2 + # ri: 1 - Set in gnb call. Please check it in agent.log + rnti: 0x44 cqi: 15 nof_ues: 2 From 6c92dca402d8665d20324bf65a768baca41ca1a2 Mon Sep 17 00:00:00 2001 From: asaezper Date: Wed, 6 Mar 2024 16:22:27 +0100 Subject: [PATCH 096/140] ci,e2e: upgrade open5gs to 2.6.6 --- .gitlab/ci/e2e/.env | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index e680b1f35a..6db6c0267c 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -1,9 +1,9 @@ SRSGNB_REGISTRY_URI=registry.gitlab.com/softwareradiosystems/srsgnb RETINA_REGISTRY_PREFIX=registry.gitlab.com/softwareradiosystems/ci/retina -RETINA_VERSION=0.44.0 +RETINA_VERSION=0.44.1 AMARISOFT_VERSION=2024-02-20 SRSUE_VERSION=23.11 -OPEN5GS_VERSION=2.6.1 +OPEN5GS_VERSION=2.6.6 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin METRICS_SERVER_VERSION=1.7.0 DPDK_VERSION=23.11 From 8d27674ed3cf76d40e60fd369c29d149980b3a2f Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Wed, 6 Mar 2024 16:14:04 +0100 Subject: [PATCH 097/140] sched: clear PDCCH allocation in resource grid upon cancelling last allocated PDCCH --- lib/scheduler/cell/resource_grid.cpp | 20 +++++++++++++++++++ lib/scheduler/cell/resource_grid.h | 10 ++++++++++ .../pdcch_slot_resource_allocator.cpp | 6 ++++++ 3 files changed, 36 insertions(+) diff --git a/lib/scheduler/cell/resource_grid.cpp b/lib/scheduler/cell/resource_grid.cpp index 415b331117..1a1eaef4dc 100644 --- a/lib/scheduler/cell/resource_grid.cpp +++ b/lib/scheduler/cell/resource_grid.cpp @@ -57,6 +57,20 @@ void carrier_subslot_resource_grid::fill(ofdm_symbol_range symbols, span crb_list) +{ + srsran_sanity_check(symbols.stop() <= NOF_OFDM_SYM_PER_SLOT_NORMAL_CP, "OFDM symbols out-of-bounds"); + + // carrier bitmap RB bit=0 corresponds to CRB=carrier offset. Thus, we need to shift the CRB interval. + for (unsigned i = symbols.start(); i < symbols.stop(); ++i) { + for (uint16_t crb : crb_list) { + srsran_sanity_check(rb_dims().contains(crb), "CRB interval out-of-bounds"); + crb -= offset(); + slot_rbs.reset(crb + i * nof_rbs()); + } + } +} + bool carrier_subslot_resource_grid::collides(ofdm_symbol_range symbols, crb_interval crbs) const { srsran_sanity_check(rb_dims().contains(crbs), "CRB interval out-of-bounds"); @@ -165,6 +179,12 @@ void cell_slot_resource_grid::fill(subcarrier_spacing scs, ofdm_symbol_range ofd carrier.subslot_rbs.fill(ofdm_symbols, crbs); } +void cell_slot_resource_grid::clear(subcarrier_spacing scs, ofdm_symbol_range ofdm_symbols, span crbs) +{ + auto& carrier = get_carrier(scs); + carrier.subslot_rbs.clear(ofdm_symbols, crbs); +} + bool cell_slot_resource_grid::collides(grant_info grant) const { const carrier_resource_grid& carrier = get_carrier(grant.scs); diff --git a/lib/scheduler/cell/resource_grid.h b/lib/scheduler/cell/resource_grid.h index cb276ba11a..16a8a392e4 100644 --- a/lib/scheduler/cell/resource_grid.h +++ b/lib/scheduler/cell/resource_grid.h @@ -87,6 +87,11 @@ class carrier_subslot_resource_grid /// \param crbs List of CRBs, where CRB=0 corresponds to the CRB closest to pointA. void fill(ofdm_symbol_range symbols, span crb_list); + /// Clears allocated symbol x CRB list in the carrier resource grid. + /// \param symbols OFDM symbol interval of the allocation. Interval must fall within [0, 14). + /// \param crbs List of CRBs, where CRB=0 corresponds to the CRB closest to pointA. + void clear(ofdm_symbol_range symbols, span crb_list); + /// Checks whether the provided symbol x CRB range collides with any other allocation in the carrier resource grid. /// \param symbols OFDM symbol interval of the allocation. Interval must fall within [0, 14). /// \param crbs CRB interval, where CRB=0 corresponds to the CRB closest to pointA. @@ -146,6 +151,11 @@ class cell_slot_resource_grid void fill(grant_info grant); void fill(subcarrier_spacing scs, ofdm_symbol_range ofdm_symbols, span crbs); + /// Clears allocated symbol x RB range in the cell resource grid. + /// \param symbols OFDM symbol interval of the allocation. + /// \param prbs PRB interval of the allocation. PRB=0 corresponds to the first PRB of the BWP. + void clear(subcarrier_spacing scs, ofdm_symbol_range ofdm_symbols, span crbs); + /// Checks whether the provided symbol x RB range collides with any other allocation in the cell resource grid. /// \param grant contains the symbol x RB range whose available we want to check. /// \return true if at least one symbol x RB of grant is currently occupied in the resource grid. diff --git a/lib/scheduler/pdcch_scheduling/pdcch_slot_resource_allocator.cpp b/lib/scheduler/pdcch_scheduling/pdcch_slot_resource_allocator.cpp index 0d4d7a7565..3aea01677d 100644 --- a/lib/scheduler/pdcch_scheduling/pdcch_slot_resource_allocator.cpp +++ b/lib/scheduler/pdcch_scheduling/pdcch_slot_resource_allocator.cpp @@ -83,6 +83,12 @@ bool pdcch_slot_allocator::cancel_last_pdcch(cell_slot_resource_allocator& slot_ return false; } + // Clear allocation on resource grid. + const coreset_configuration& cs_cfg = *records.back().pdcch_ctx->coreset_cfg; + const crb_index_list& pdcch_crbs = records.back().pdcch_candidate_crbs[dfs_tree.back().dci_iter_index]; + ofdm_symbol_range symbols{0, (uint8_t)cs_cfg.duration}; + slot_alloc.dl_res_grid.clear(records.back().pdcch_ctx->bwp_cfg->scs, symbols, pdcch_crbs); + dfs_tree.pop_back(); records.pop_back(); return true; From 13abdfcd8c6326f3eb47e340077d7ba67452d688 Mon Sep 17 00:00:00 2001 From: faluco Date: Thu, 22 Feb 2024 18:48:54 +0100 Subject: [PATCH 098/140] support: Refactor interface of transport layer address. Clean up uses of this class and adjust code style. --- apps/gnb/gnb_du_factory.cpp | 5 +- .../f1u_local_bearer_adapter.h | 4 +- include/srsran/ran/up_transport_layer_info.h | 31 ++-- .../support/io/transport_layer_address.h | 46 +++--- lib/cu_up/pdu_session_manager_impl.cpp | 37 +++-- .../du/procedures/f1ap_du_ue_context_common.h | 43 +++--- .../network/transport_layer_address.cpp | 134 +++++++++--------- .../benchmarks/du_high/du_high_benchmark.cpp | 20 +-- .../du_high/test_utils/du_high_test_bench.cpp | 2 +- .../du_high_cu/du_high_cu_test_simulator.cpp | 24 ++-- .../test_doubles/f1ap/f1ap_test_messages.cpp | 4 +- .../cu_cp/du_processor_test_messages.cpp | 6 +- tests/unittests/cu_cp/test_helpers.h | 2 +- .../cu_up/pdu_session_manager_test.h | 6 +- .../du_manager/du_manager_test_helpers.cpp | 4 +- .../du_manager/du_ue/du_bearer_test.cpp | 2 +- .../du_manager/du_ue/ue_manager_test.cpp | 2 +- .../e1ap/common/e1ap_cu_cp_test_messages.cpp | 2 +- tests/unittests/e1ap/common/test_helpers.h | 2 +- .../f1ap/common/f1ap_asn1_helpers_test.cpp | 4 +- .../f1ap/common/f1ap_cu_test_messages.cpp | 3 +- .../f1ap/du/f1ap_du_test_helpers.cpp | 10 +- .../f1ap_du_ue_context_modification_test.cpp | 2 +- ...1ap_du_ue_context_setup_procedure_test.cpp | 5 +- .../f1u/common/f1u_connector_test.cpp | 14 +- .../f1u/cu_up/f1u_cu_up_bearer_test.cpp | 22 +-- tests/unittests/f1u/du/f1u_du_bearer_test.cpp | 16 ++- tests/unittests/ngap/ngap_test_messages.cpp | 6 +- tests/unittests/ngap/ngap_validators_test.cpp | 2 +- .../network/transport_layer_address_test.cpp | 29 ++-- 30 files changed, 263 insertions(+), 226 deletions(-) diff --git a/apps/gnb/gnb_du_factory.cpp b/apps/gnb/gnb_du_factory.cpp index da97566bb7..d4efb6541d 100644 --- a/apps/gnb/gnb_du_factory.cpp +++ b/apps/gnb/gnb_du_factory.cpp @@ -154,8 +154,9 @@ std::vector> srsran::make_gnb_dus(const gnb_appconfig& du_hi_cfg.rlc_p = &rlc_p; du_hi_cfg.gnb_du_id = du_insts.size() + 1; du_hi_cfg.gnb_du_name = fmt::format("srsdu{}", du_hi_cfg.gnb_du_id); - du_hi_cfg.du_bind_addr = {fmt::format("127.0.0.{}", du_hi_cfg.gnb_du_id)}; - du_hi_cfg.mac_cfg = generate_mac_expert_config(gnb_cfg); + du_hi_cfg.du_bind_addr = + transport_layer_address::create_from_string(fmt::format("127.0.0.{}", du_hi_cfg.gnb_du_id)); + du_hi_cfg.mac_cfg = generate_mac_expert_config(gnb_cfg); // Assign different initial C-RNTIs to different DUs. du_hi_cfg.mac_cfg.initial_crnti = to_rnti(0x4601 + (0x1000 * du_insts.size())); du_hi_cfg.sched_ue_metrics_notifier = metrics_hub.get_scheduler_ue_metrics_source("DU " + std::to_string(i)); diff --git a/include/srsran/f1u/local_connector/f1u_local_bearer_adapter.h b/include/srsran/f1u/local_connector/f1u_local_bearer_adapter.h index a5d8772d48..5882513c66 100644 --- a/include/srsran/f1u/local_connector/f1u_local_bearer_adapter.h +++ b/include/srsran/f1u/local_connector/f1u_local_bearer_adapter.h @@ -59,8 +59,8 @@ class f1u_dl_local_adapter : public srs_cu_up::f1u_tx_pdu_notifier private: srs_cu_up::f1u_bearer_logger logger; - srs_du::f1u_rx_pdu_handler* handler = nullptr; - optional dl_tnl_info = {}; + srs_du::f1u_rx_pdu_handler* handler = nullptr; + optional dl_tnl_info; }; class f1u_tx_delivery_local_adapter : public srs_cu_up::f1u_rx_delivery_notifier diff --git a/include/srsran/ran/up_transport_layer_info.h b/include/srsran/ran/up_transport_layer_info.h index b73c616683..9715632001 100644 --- a/include/srsran/ran/up_transport_layer_info.h +++ b/include/srsran/ran/up_transport_layer_info.h @@ -17,14 +17,23 @@ namespace srsran { /// \brief Identifier for F1-U transport layer associated to a DRB. struct up_transport_layer_info { - transport_layer_address tp_address{"0.0.0.0"}; + transport_layer_address tp_address = transport_layer_address::create_from_string("0.0.0.0"); gtpu_teid_t gtp_teid; + up_transport_layer_info() = default; + + up_transport_layer_info(const transport_layer_address& tp_address_, gtpu_teid_t gtp_teid_) : + tp_address(tp_address_), gtp_teid(gtp_teid_) + { + } + bool operator==(const up_transport_layer_info& other) const { return tp_address == other.tp_address and gtp_teid == other.gtp_teid; } + bool operator!=(const up_transport_layer_info& other) const { return not(*this == other); } + bool operator<(const up_transport_layer_info& other) const { return gtp_teid < other.gtp_teid or (gtp_teid == other.gtp_teid and tp_address < other.tp_address); @@ -46,25 +55,27 @@ void up_transport_layer_info_to_asn1(Asn1Type& asn1obj, const up_transport_layer /// \param asn1obj ASN.1 object which is going to be converted. /// \return UP Transport Layer Info object where the result of the conversion is stored. template -up_transport_layer_info asn1_to_up_transport_layer_info(Asn1Type& asn1obj) +up_transport_layer_info asn1_to_up_transport_layer_info(const Asn1Type& asn1obj) { - up_transport_layer_info ret; - ret.gtp_teid = int_to_gtpu_teid(asn1obj.gtp_tunnel().gtp_teid.to_number()); - ret.tp_address.from_bitstring(asn1obj.gtp_tunnel().transport_layer_address.to_string()); - return ret; + return {transport_layer_address::create_from_bitstring(asn1obj.gtp_tunnel().transport_layer_address.to_string()), + int_to_gtpu_teid(asn1obj.gtp_tunnel().gtp_teid.to_number())}; } } // namespace srsran +namespace std { + template <> -struct std::hash { - std::size_t operator()(const srsran::up_transport_layer_info& s) const noexcept +struct hash { + size_t operator()(const srsran::up_transport_layer_info& s) const noexcept { - return (std::hash{}(s.tp_address) ^ - (std::hash{}(s.gtp_teid.value()) << 1U) >> 1U); + return (hash{}(s.tp_address) ^ + (hash{}(s.gtp_teid.value()) << 1U) >> 1U); } }; +} // namespace std + namespace fmt { template <> diff --git a/include/srsran/support/io/transport_layer_address.h b/include/srsran/support/io/transport_layer_address.h index 1e8bb3e3c3..3fe6796f85 100644 --- a/include/srsran/support/io/transport_layer_address.h +++ b/include/srsran/support/io/transport_layer_address.h @@ -21,30 +21,32 @@ namespace srsran { class transport_layer_address { public: + /// Underlying native type used to store a transport layer address. + using native_type = ::sockaddr_storage; + transport_layer_address() = default; - transport_layer_address(const std::string& ip_str) { from_string(ip_str); } - /// \brief Converts a string with an IPv4 address with format X.X.X.X or with an IPv6 address with - /// format X:X:X:X:X:X:X:X to a transport_layer_address. - transport_layer_address& from_string(const std::string& ip_str); + /// Creates a transport_layer_address object from a string with an IPv4 address with format X.X.X.X or with an IPv6 + /// address with format X:X:X:X:X:X:X:X. + static transport_layer_address create_from_string(const std::string& ip_str); + + /// Creates a transport_layer_address object from a string of bits (each character is base 2). + static transport_layer_address create_from_bitstring(const std::string& bit_str); /// Converts the transport_layer_address to an IPv4 or IPv6 string. std::string to_string() const { return fmt::format("{}", *this); } - /// Converts a string of bits (each character is base 2) to a transport_layer_address. - transport_layer_address& from_bitstring(std::string bit_str); - /// Converts the transport layer address to a string of bits (each character is base 2). std::string to_bitstring() const; - /// Extracts the posix representation of the transport layer address. - const struct sockaddr_storage& native() const { return addr; } - struct sockaddr_storage& native() { return addr; } + /// Extracts the POSIX representation of the transport layer address. + const native_type& native() const { return addr; } + native_type& native() { return addr; } /// Compares two transport_layer_addresses. bool operator==(const transport_layer_address& other) const; bool operator!=(const transport_layer_address& other) const { return not(*this == other); } - bool operator==(const std::string& ip_str) const { return *this == transport_layer_address(ip_str); } + bool operator==(const std::string& ip_str) const { return *this == create_from_string(ip_str); } bool operator!=(const std::string& ip_str) const { return not(*this == ip_str); } bool operator<(const transport_layer_address& other) const; @@ -53,18 +55,20 @@ class transport_layer_address bool operator>(const transport_layer_address& other) const { return not(*this <= other); } private: - struct sockaddr_storage addr; + explicit transport_layer_address(const native_type& addr_) : addr(addr_) {} + +private: + native_type addr; }; } // namespace srsran +namespace std { template <> -struct std::hash { - std::size_t operator()(const srsran::transport_layer_address& s) const noexcept - { - return std::hash{}(s.to_string()); - } +struct hash { + size_t operator()(const srsran::transport_layer_address& s) const noexcept { return hash{}(s.to_string()); } }; +} // namespace std namespace fmt { @@ -75,7 +79,13 @@ struct formatter : public formatter decltype(std::declval().out()) { char ip_addr[NI_MAXHOST]; - if (getnameinfo((sockaddr*)&s.native(), sizeof(s), ip_addr, NI_MAXHOST, nullptr, 0, NI_NUMERICHOST) != 0) { + if (::getnameinfo(reinterpret_cast(&s.native()), + sizeof(srsran::transport_layer_address::native_type), + ip_addr, + sizeof(ip_addr), + nullptr, + 0, + NI_NUMERICHOST) != 0) { return format_to(ctx.out(), "invalid_addr"); } diff --git a/lib/cu_up/pdu_session_manager_impl.cpp b/lib/cu_up/pdu_session_manager_impl.cpp index 86f02ad1c2..40bb772b73 100644 --- a/lib/cu_up/pdu_session_manager_impl.cpp +++ b/lib/cu_up/pdu_session_manager_impl.cpp @@ -189,10 +189,10 @@ drb_setup_result pdu_session_manager_impl::handle_drb_to_setup_item(pdu_session& } gtpu_teid_t f1u_ul_teid = ret.value(); - up_transport_layer_info f1u_ul_tunnel_addr; - f1u_ul_tunnel_addr.tp_address.from_string(net_config.f1u_bind_addr); - f1u_ul_tunnel_addr.gtp_teid = f1u_ul_teid; - new_drb->f1u = f1u_gw.create_cu_bearer(ue_index, + up_transport_layer_info f1u_ul_tunnel_addr(transport_layer_address::create_from_string(net_config.f1u_bind_addr), + f1u_ul_teid); + + new_drb->f1u = f1u_gw.create_cu_bearer(ue_index, drb_to_setup.drb_id, f1u_ul_tunnel_addr, new_drb->f1u_to_pdcp_adapter, @@ -200,8 +200,8 @@ drb_setup_result pdu_session_manager_impl::handle_drb_to_setup_item(pdu_session& ue_ul_exec, ue_dl_timer_factory, ue_inactivity_timer); - new_drb->f1u_ul_teid = f1u_ul_teid; - drb_result.gtp_tunnel = f1u_ul_tunnel_addr; + new_drb->f1u_ul_teid = f1u_ul_teid; + drb_result.gtp_tunnel = f1u_ul_tunnel_addr; // Connect F1-U's "F1-U->PDCP adapter" directly to PDCP new_drb->f1u_to_pdcp_adapter.connect_pdcp(new_drb->pdcp->get_rx_lower_interface(), @@ -251,10 +251,8 @@ pdu_session_setup_result pdu_session_manager_impl::setup_pdu_session(const e1ap_ // Allocate local TEID new_session->local_teid = allocate_local_teid(new_session->pdu_session_id); - up_transport_layer_info n3_dl_tunnel_addr; - n3_dl_tunnel_addr.tp_address.from_string(net_config.n3_bind_addr); - n3_dl_tunnel_addr.gtp_teid = new_session->local_teid; - pdu_session_result.gtp_tunnel = n3_dl_tunnel_addr; + pdu_session_result.gtp_tunnel = up_transport_layer_info( + transport_layer_address::create_from_string(net_config.n3_bind_addr), new_session->local_teid); // Create SDAP entity sdap_entity_creation_message sdap_msg = {ue_index, session.pdu_session_id, &new_session->sdap_to_gtpu_adapter}; @@ -374,9 +372,8 @@ pdu_session_manager_impl::modify_pdu_session(const e1ap_pdu_session_res_to_modif drb->f1u_ul_teid = ret.value(); // Create UL UP TNL address. - up_transport_layer_info f1u_ul_tunnel_addr; - f1u_ul_tunnel_addr.tp_address.from_string(net_config.f1u_bind_addr); - f1u_ul_tunnel_addr.gtp_teid = drb->f1u_ul_teid; + up_transport_layer_info f1u_ul_tunnel_addr(transport_layer_address::create_from_string(net_config.f1u_bind_addr), + drb->f1u_ul_teid); // create new F1-U and connect it. This will automatically disconnect the old F1-U. drb->f1u = f1u_gw.create_cu_bearer(ue_index, @@ -394,10 +391,10 @@ pdu_session_manager_impl::modify_pdu_session(const e1ap_pdu_session_res_to_modif // F1-U apply modification if (!drb_to_mod.dl_up_params.empty()) { - up_transport_layer_info f1u_ul_tunnel_addr; - f1u_ul_tunnel_addr.tp_address.from_string(net_config.f1u_bind_addr); - f1u_ul_tunnel_addr.gtp_teid = drb_iter->second->f1u_ul_teid; - f1u_gw.attach_dl_teid(f1u_ul_tunnel_addr, drb_to_mod.dl_up_params[0].up_tnl_info); + f1u_gw.attach_dl_teid( + up_transport_layer_info(transport_layer_address::create_from_string(net_config.f1u_bind_addr), + drb_iter->second->f1u_ul_teid), + drb_to_mod.dl_up_params[0].up_tnl_info); drb_iter->second->pdcp_to_f1u_adapter.connect_f1u(drb_iter->second->f1u->get_tx_sdu_handler()); } @@ -484,10 +481,8 @@ void pdu_session_manager_impl::remove_pdu_session(pdu_session_id_t pdu_session_i auto& pdu_session = pdu_sessions.at(pdu_session_id); for (const auto& drb : pdu_session->drbs) { logger.log_debug("Disconnecting CU bearer with UL-TEID={}", drb.second->f1u_ul_teid); - up_transport_layer_info f1u_ul_tunnel_addr; - f1u_ul_tunnel_addr.tp_address.from_string(net_config.f1u_bind_addr); - f1u_ul_tunnel_addr.gtp_teid = drb.second->f1u_ul_teid; - f1u_gw.disconnect_cu_bearer(f1u_ul_tunnel_addr); + f1u_gw.disconnect_cu_bearer(up_transport_layer_info( + transport_layer_address::create_from_string(net_config.f1u_bind_addr), drb.second->f1u_ul_teid)); if (f1u_teid_allocator.release_teid(drb.second->f1u_ul_teid)) { logger.log_error( "{} could not remove ul_teid at session termination. ul_teid={}", pdu_session_id, drb.second->f1u_ul_teid); diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h index 6bc4764e8f..7ec2aa15fb 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_common.h @@ -16,55 +16,56 @@ namespace srsran { namespace srs_du { -/// \brief Creates a \c srb_id_t from ASN.1 type +/// \brief Creates a \c srb_id_t from ASN.1 type. /// -/// This function is used by the following procedures +/// This function is used by the following procedures: /// - f1ap_du_ue_context_setup_procedure /// - f1ap_du_ue_context_modification_procedure /// -/// \param srb_item ASN.1 item with SRB-specific parameters to be setup -/// \return srb_id_t object +/// \param srb_item ASN.1 item with SRB-specific parameters to be setup. +/// \return srb_id_t object. template srb_id_t make_srb_id(const Asn1Type& srb_item) { - return (srb_id_t)srb_item.srb_id; + return static_cast(srb_item.srb_id); } -/// \brief Creates a \c f1ap_drb_to_setup from ASN.1 type +/// \brief Creates a \c f1ap_drb_to_setup from ASN.1 type. /// -/// This function is used by the following procedures +/// This function is used by the following procedures: /// - f1ap_du_ue_context_setup_procedure /// - f1ap_du_ue_context_modification_procedure /// -/// \param drb_item ASN.1 item with DRB-specific parameters to be setup -/// \return f1ap_drb_to_setup object +/// \param drb_item ASN.1 item with DRB-specific parameters to be setup. +/// \return f1ap_drb_to_setup object. template f1ap_drb_to_setup make_drb_to_setup(const Asn1Type& drb_item) { f1ap_drb_to_setup drb_obj; - drb_obj.drb_id = (drb_id_t)drb_item.drb_id; - drb_obj.mode = (drb_rlc_mode)(unsigned)drb_item.rlc_mode; - drb_obj.uluptnl_info_list.resize(drb_item.ul_up_tnl_info_to_be_setup_list.size()); - for (unsigned j = 0; j != drb_obj.uluptnl_info_list.size(); ++j) { - drb_obj.uluptnl_info_list[j] = - asn1_to_up_transport_layer_info(drb_item.ul_up_tnl_info_to_be_setup_list[j].ul_up_tnl_info); - } + + drb_obj.drb_id = static_cast(drb_item.drb_id); + drb_obj.mode = static_cast(static_cast(drb_item.rlc_mode)); drb_obj.five_qi = uint_to_five_qi( drb_item.qos_info.choice_ext().value().drb_info().drb_qos.qos_characteristics.non_dyn_5qi().five_qi); + drb_obj.uluptnl_info_list.reserve(drb_item.ul_up_tnl_info_to_be_setup_list.size()); + for (const auto& tnl_info : drb_item.ul_up_tnl_info_to_be_setup_list) { + drb_obj.uluptnl_info_list.push_back(asn1_to_up_transport_layer_info(tnl_info.ul_up_tnl_info)); + } + return drb_obj; } -/// \brief Creates a \c drb_id_t from ASN.1 type +/// \brief Creates a \c drb_id_t from ASN.1 type. /// -/// This function is used by the following procedures +/// This function is used by the following procedures: /// - f1ap_du_ue_context_modification_procedure /// -/// \param drb_item ASN.1 item with DRB-specific parameters to be removed -/// \return drb_id_t object +/// \param drb_item ASN.1 item with DRB-specific parameters to be removed. +/// \return drb_id_t object. template drb_id_t make_drb_id(const Asn1Type& drb_item) { - return (drb_id_t)drb_item.drb_id; + return static_cast(drb_item.drb_id); } } // namespace srs_du diff --git a/lib/support/network/transport_layer_address.cpp b/lib/support/network/transport_layer_address.cpp index 0ee7b9e88b..b10b01dc7d 100644 --- a/lib/support/network/transport_layer_address.cpp +++ b/lib/support/network/transport_layer_address.cpp @@ -11,97 +11,101 @@ #include "srsran/support/io/transport_layer_address.h" #include "srsran/support/srsran_assert.h" #include -#include using namespace srsran; -transport_layer_address& transport_layer_address::from_string(const std::string& ip_str) +transport_layer_address transport_layer_address::create_from_string(const std::string& ip_str) { - struct addrinfo* results; + ::addrinfo* results; + native_type addr; - int err = getaddrinfo(ip_str.c_str(), nullptr, nullptr, &results); - srsran_assert(err == 0, "Getaddrinfo error: {} - {}", ip_str, gai_strerror(err)); + int err = ::getaddrinfo(ip_str.c_str(), nullptr, nullptr, &results); + srsran_assert(err == 0, "Getaddrinfo error: {} - {}", ip_str, ::gai_strerror(err)); - // store address - memcpy(&addr, results->ai_addr, results->ai_addrlen); + // Store address. + std::memcpy(&addr, results->ai_addr, results->ai_addrlen); - freeaddrinfo(results); + ::freeaddrinfo(results); - return *this; + return transport_layer_address(addr); } -transport_layer_address& transport_layer_address::from_bitstring(std::string bit_str) +transport_layer_address transport_layer_address::create_from_bitstring(const std::string& bit_str) { srsran_assert(bit_str.length() < 160, "Combined IPv4 and IPv6 addresses are currently not supported"); - std::string ip_str; - - if (bit_str.length() == 32) { // see see TS 38.414: 32 bits in case of IPv4 address according to IETF RFC 791 - ip_str = fmt::format("{}.{}.{}.{}", - std::stoi(bit_str.substr(0, 8), nullptr, 2), - std::stoi(bit_str.substr(8, 8), nullptr, 2), - std::stoi(bit_str.substr(16, 8), nullptr, 2), - std::stoi(bit_str.substr(24, 8), nullptr, 2)); - } else if (bit_str.length() == - 128) { // see see TS 38.414: 128 bits in case of IPv6 address according to IETF RFC 8200 - ip_str = fmt::format("{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}", - std::stoi(bit_str.substr(0, 16), nullptr, 2), - std::stoi(bit_str.substr(16, 16), nullptr, 2), - std::stoi(bit_str.substr(32, 16), nullptr, 2), - std::stoi(bit_str.substr(48, 16), nullptr, 2), - std::stoi(bit_str.substr(64, 16), nullptr, 2), - std::stoi(bit_str.substr(80, 16), nullptr, 2), - std::stoi(bit_str.substr(96, 16), nullptr, 2), - std::stoi(bit_str.substr(112, 16), nullptr, 2)); - - } else { // see see TS 38.414: 160 bits if both IPv4 and IPv6 addresses are signalled, in which case the IPv4 - // address is contained in the first 32 bits - // TODO: Support 160 bit transport layer addresses + // See TS 38.414: 32 bits in case of IPv4 address according to IETF RFC 791. + if (bit_str.length() == 32) { + std::string ip_str = fmt::format("{}.{}.{}.{}", + std::stoi(bit_str.substr(0, 8), nullptr, 2), + std::stoi(bit_str.substr(8, 8), nullptr, 2), + std::stoi(bit_str.substr(16, 8), nullptr, 2), + std::stoi(bit_str.substr(24, 8), nullptr, 2)); + return create_from_string(ip_str); } - return from_string(ip_str); + // See TS 38.414: 128 bits in case of IPv6 address according to IETF RFC 8200. + if (bit_str.length() == 128) { + std::string ip_str = fmt::format("{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}", + std::stoi(bit_str.substr(0, 16), nullptr, 2), + std::stoi(bit_str.substr(16, 16), nullptr, 2), + std::stoi(bit_str.substr(32, 16), nullptr, 2), + std::stoi(bit_str.substr(48, 16), nullptr, 2), + std::stoi(bit_str.substr(64, 16), nullptr, 2), + std::stoi(bit_str.substr(80, 16), nullptr, 2), + std::stoi(bit_str.substr(96, 16), nullptr, 2), + std::stoi(bit_str.substr(112, 16), nullptr, 2)); + return create_from_string(ip_str); + } + + // See TS 38.414: 160 bits if both IPv4 and IPv6 addresses are signalled, in which case the IPv4 address is contained + // in the first 32 bits. + // TODO: Support 160 bit transport layer addresses + + return create_from_string(""); } std::string transport_layer_address::to_bitstring() const { - std::string bitstr; - - char ip_addr[NI_MAXHOST]; - getnameinfo((sockaddr*)&addr, sizeof(addr), ip_addr, NI_MAXHOST, nullptr, 0, NI_NUMERICHOST); - - if (((sockaddr*)&addr)->sa_family == AF_INET) { - std::string ip_str = ip_addr; - std::string delim = "."; - - auto start = 0U; - auto end = ip_str.find(delim); + char ip_addr[NI_MAXHOST]; + const auto* saddr = reinterpret_cast(&addr); + ::getnameinfo(saddr, sizeof(addr), ip_addr, sizeof(ip_addr), nullptr, 0, NI_NUMERICHOST); + std::string ip_str = ip_addr; + + if (saddr->sa_family == AF_INET) { + std::string bitstr; + char delim = '.'; + auto start = 0U; + auto end = ip_str.find(delim); while (end != std::string::npos) { - bitstr = bitstr + fmt::format("{:08b}", std::stoul(ip_str.substr(start, end - start))); - start = end + delim.length(); - end = ip_str.find(delim, start); + bitstr += fmt::format("{:08b}", std::stoul(ip_str.substr(start, end - start))); + start = end + sizeof(delim); + end = ip_str.find(delim, start); } - bitstr = bitstr + fmt::format("{:08b}", std::stoul(ip_str.substr(start, end))); - } else { - std::string ip_str = ip_addr; - std::string delim = ":"; + bitstr += fmt::format("{:08b}", std::stoul(ip_str.substr(start, end))); - auto start = 0U; - auto end = ip_str.find(delim); - while (end != std::string::npos) { - bitstr = bitstr + fmt::format("{:016b}", std::stoul(ip_str.substr(start, end - start), nullptr, 16)); - start = end + delim.length(); - end = ip_str.find(delim, start); - } - bitstr = bitstr + fmt::format("{:016b}", std::stoul(ip_str.substr(start, end), nullptr, 16)); + return bitstr; + } + + std::string bitstr; + char delim = ':'; + auto start = 0U; + auto end = ip_str.find(delim); + while (end != std::string::npos) { + bitstr += fmt::format("{:016b}", std::stoul(ip_str.substr(start, end - start), nullptr, 16)); + start = end + sizeof(delim); + end = ip_str.find(delim, start); } + bitstr += fmt::format("{:016b}", std::stoul(ip_str.substr(start, end), nullptr, 16)); return bitstr; } bool transport_layer_address::operator==(const transport_layer_address& other) const { - for (long unsigned int i = 0; i < sizeof(((sockaddr*)&addr)->sa_data); i++) { - if (((sockaddr*)&addr)->sa_data[i] != ((sockaddr*)&other)->sa_data[i]) { + const auto* saddr = reinterpret_cast(&addr); + for (unsigned i = 0; i != sizeof(saddr->sa_data); ++i) { + if (saddr->sa_data[i] != reinterpret_cast(&other)->sa_data[i]) { return false; } } @@ -111,10 +115,12 @@ bool transport_layer_address::operator==(const transport_layer_address& other) c bool transport_layer_address::operator<(const transport_layer_address& other) const { - for (long unsigned int i = 0; i < sizeof(((sockaddr*)&addr)->sa_data); i++) { - if (((sockaddr*)&addr)->sa_data[i] < ((sockaddr*)&other)->sa_data[i]) { + const auto* saddr = reinterpret_cast(&addr); + for (unsigned i = 0; i != sizeof(saddr->sa_data); ++i) { + if (saddr->sa_data[i] < reinterpret_cast(&other)->sa_data[i]) { return true; } } + return false; } diff --git a/tests/benchmarks/du_high/du_high_benchmark.cpp b/tests/benchmarks/du_high/du_high_benchmark.cpp index 3ebfce741a..286f5afdd4 100644 --- a/tests/benchmarks/du_high/du_high_benchmark.cpp +++ b/tests/benchmarks/du_high/du_high_benchmark.cpp @@ -536,16 +536,16 @@ class du_high_bench report_fatal_error_if_not(bsr_mac_subpdu.append(lbsr_buff_sz), "Failed to allocate PDU"); // Instantiate a DU-high object. - cfg.gnb_du_id = 1; - cfg.gnb_du_name = fmt::format("srsgnb{}", cfg.gnb_du_id); - cfg.du_bind_addr = fmt::format("127.0.0.{}", cfg.gnb_du_id); - cfg.exec_mapper = &workers.du_high_exec_mapper; - cfg.f1c_client = &sim_cu_cp; - cfg.f1u_gw = &sim_cu_up; - cfg.phy_adapter = &sim_phy; - cfg.timers = &timers; - cfg.cells = {config_helpers::make_default_du_cell_config(params)}; - cfg.sched_cfg = config_helpers::make_default_scheduler_expert_config(); + cfg.gnb_du_id = 1; + cfg.gnb_du_name = fmt::format("srsgnb{}", cfg.gnb_du_id); + cfg.du_bind_addr = transport_layer_address::create_from_string(fmt::format("127.0.0.{}", cfg.gnb_du_id)); + cfg.exec_mapper = &workers.du_high_exec_mapper; + cfg.f1c_client = &sim_cu_cp; + cfg.f1u_gw = &sim_cu_up; + cfg.phy_adapter = &sim_phy; + cfg.timers = &timers; + cfg.cells = {config_helpers::make_default_du_cell_config(params)}; + cfg.sched_cfg = config_helpers::make_default_scheduler_expert_config(); cfg.sched_cfg.ue.pdsch_nof_rbs = {1, max_nof_rbs_per_dl_grant}; cfg.mac_cfg = mac_expert_config{.configs = {{10000, 10000, 10000}}}; cfg.qos = config_helpers::make_default_du_qos_config_list(1000); diff --git a/tests/integrationtests/du_high/test_utils/du_high_test_bench.cpp b/tests/integrationtests/du_high/test_utils/du_high_test_bench.cpp index 974b680a04..d9f62048b4 100644 --- a/tests/integrationtests/du_high/test_utils/du_high_test_bench.cpp +++ b/tests/integrationtests/du_high/test_utils/du_high_test_bench.cpp @@ -162,7 +162,7 @@ du_high_test_bench::du_high_test_bench() : cfg.timers = &timers; cfg.gnb_du_id = 0; cfg.gnb_du_name = "srsdu"; - cfg.du_bind_addr = {"127.0.0.1"}; + cfg.du_bind_addr = transport_layer_address::create_from_string("127.0.0.1"); cfg.cells = {config_helpers::make_default_du_cell_config()}; cfg.qos = config_helpers::make_default_du_qos_config_list(0); cfg.sched_cfg = config_helpers::make_default_scheduler_expert_config(); diff --git a/tests/integrationtests/du_high_cu/du_high_cu_test_simulator.cpp b/tests/integrationtests/du_high_cu/du_high_cu_test_simulator.cpp index 6d70b059a5..4bb37f2576 100644 --- a/tests/integrationtests/du_high_cu/du_high_cu_test_simulator.cpp +++ b/tests/integrationtests/du_high_cu/du_high_cu_test_simulator.cpp @@ -157,18 +157,18 @@ void du_high_cu_test_simulator::start_dus() srs_du::du_high_configuration& du_hi_cfg = du_ctxt.du_high_cfg; du_hi_cfg.gnb_du_name = fmt::format("srsgnb{}", du_idx + 1); du_hi_cfg.gnb_du_id = du_idx + 1; - du_hi_cfg.du_bind_addr = {fmt::format("127.0.0.{}", du_idx + 1)}; - du_hi_cfg.exec_mapper = workers.du_hi_exec_mappers[du_idx].get(); - du_hi_cfg.f1c_client = &f1c_gw; - du_hi_cfg.f1u_gw = nullptr; - du_hi_cfg.phy_adapter = &du_ctxt.phy; - du_hi_cfg.timers = &timers; - du_hi_cfg.sched_ue_metrics_notifier = &du_ctxt.ue_metrics_notifier; - du_hi_cfg.cells = cfg.dus[du_idx]; - du_hi_cfg.sched_cfg = config_helpers::make_default_scheduler_expert_config(); - du_hi_cfg.mac_p = &du_ctxt.mac_pcap; - du_hi_cfg.rlc_p = &du_ctxt.rlc_pcap; - du_ctxt.du_high_inst = make_du_high(du_hi_cfg); + du_hi_cfg.du_bind_addr = transport_layer_address::create_from_string(fmt::format("127.0.0.{}", du_idx + 1)); + du_hi_cfg.exec_mapper = workers.du_hi_exec_mappers[du_idx].get(); + du_hi_cfg.f1c_client = &f1c_gw; + du_hi_cfg.f1u_gw = nullptr; + du_hi_cfg.phy_adapter = &du_ctxt.phy; + du_hi_cfg.timers = &timers; + du_hi_cfg.sched_ue_metrics_notifier = &du_ctxt.ue_metrics_notifier; + du_hi_cfg.cells = cfg.dus[du_idx]; + du_hi_cfg.sched_cfg = config_helpers::make_default_scheduler_expert_config(); + du_hi_cfg.mac_p = &du_ctxt.mac_pcap; + du_hi_cfg.rlc_p = &du_ctxt.rlc_pcap; + du_ctxt.du_high_inst = make_du_high(du_hi_cfg); du_ctxt.du_high_inst->start(); } diff --git a/tests/test_doubles/f1ap/f1ap_test_messages.cpp b/tests/test_doubles/f1ap/f1ap_test_messages.cpp index 35c9fdff62..3891256e3f 100644 --- a/tests/test_doubles/f1ap/f1ap_test_messages.cpp +++ b/tests/test_doubles/f1ap/f1ap_test_messages.cpp @@ -39,8 +39,8 @@ static asn1::f1ap::drbs_to_be_setup_item_s generate_drb_am_setup_item(drb_id_t d drb_info.snssai.sd.from_string("0027db"); drb.rlc_mode.value = rlc_mode_opts::rlc_am; drb.ul_up_tnl_info_to_be_setup_list.resize(1); - auto& gtp_tun = drb.ul_up_tnl_info_to_be_setup_list[0].ul_up_tnl_info.set_gtp_tunnel(); - transport_layer_address addr{"127.0.0.1"}; + auto& gtp_tun = drb.ul_up_tnl_info_to_be_setup_list[0].ul_up_tnl_info.set_gtp_tunnel(); + auto addr = transport_layer_address::create_from_string("127.0.0.1"); gtp_tun.transport_layer_address.from_string(addr.to_bitstring()); gtp_tun.gtp_teid.from_number(1); diff --git a/tests/unittests/cu_cp/du_processor_test_messages.cpp b/tests/unittests/cu_cp/du_processor_test_messages.cpp index 6703e68363..d228d82bd8 100644 --- a/tests/unittests/cu_cp/du_processor_test_messages.cpp +++ b/tests/unittests/cu_cp/du_processor_test_messages.cpp @@ -122,9 +122,9 @@ srsran::srs_cu_cp::generate_pdu_session_resource_setup(unsigned num_pdu_sessions item.pdu_session_aggregate_maximum_bit_rate_dl = 100; item.pdu_session_aggregate_maximum_bit_rate_ul = 100; - item.ul_ngu_up_tnl_info = {transport_layer_address{"127.0.0.1"}, int_to_gtpu_teid(0x1)}; - item.pdu_session_type = "ipv4"; - item.security_ind = {}; + item.ul_ngu_up_tnl_info = {transport_layer_address::create_from_string("127.0.0.1"), int_to_gtpu_teid(0x1)}; + item.pdu_session_type = "ipv4"; + item.security_ind = {}; for (unsigned k = 0; k < num_qos_flows; ++k) { qos_flow_setup_request_item qos_item; diff --git a/tests/unittests/cu_cp/test_helpers.h b/tests/unittests/cu_cp/test_helpers.h index 3d224fe287..f8ded3b0bf 100644 --- a/tests/unittests/cu_cp/test_helpers.h +++ b/tests/unittests/cu_cp/test_helpers.h @@ -200,7 +200,7 @@ struct dummy_du_processor_e1ap_control_notifier : public du_processor_e1ap_contr // add one UP transport item e1ap_up_params_item up_item; up_item.cell_group_id = 0; - up_item.up_tnl_info = {transport_layer_address{"127.0.0.1"}, int_to_gtpu_teid(0x1)}; + up_item.up_tnl_info = {transport_layer_address::create_from_string("127.0.0.1"), int_to_gtpu_teid(0x1)}; drb_item.ul_up_transport_params.push_back(up_item); res_setup_item.drb_setup_list_ng_ran.emplace(drb_id, drb_item); diff --git a/tests/unittests/cu_up/pdu_session_manager_test.h b/tests/unittests/cu_up/pdu_session_manager_test.h index 0aa545f4ab..b19e07aa36 100644 --- a/tests/unittests/cu_up/pdu_session_manager_test.h +++ b/tests/unittests/cu_up/pdu_session_manager_test.h @@ -98,9 +98,11 @@ generate_pdu_session_res_to_setup_item(pdu_session_id_t psi, drb_id_t drb_id, qo pdu_session_setup_item.security_ind.confidentiality_protection_ind = confidentiality_protection_indication_t::not_needed; pdu_session_setup_item.pdu_session_res_dl_ambr = 330000000; - pdu_session_setup_item.ng_ul_up_tnl_info.tp_address.from_bitstring("01111111000000000000000000000001"); + pdu_session_setup_item.ng_ul_up_tnl_info.tp_address = + transport_layer_address::create_from_bitstring("01111111000000000000000000000001"); pdu_session_setup_item.ng_ul_up_tnl_info.gtp_teid = int_to_gtpu_teid(0x12345678); - pdu_session_setup_item.ng_ul_up_tnl_info = {transport_layer_address{"0.0.0.0"}, int_to_gtpu_teid(0)}; + pdu_session_setup_item.ng_ul_up_tnl_info = {transport_layer_address::create_from_string("0.0.0.0"), + int_to_gtpu_teid(0)}; e1ap_drb_to_setup_item_ng_ran drb_to_setup_item; drb_to_setup_item.drb_id = drb_id; diff --git a/tests/unittests/du_manager/du_manager_test_helpers.cpp b/tests/unittests/du_manager/du_manager_test_helpers.cpp index a393c6a348..4588ecfa6c 100644 --- a/tests/unittests/du_manager/du_manager_test_helpers.cpp +++ b/tests/unittests/du_manager/du_manager_test_helpers.cpp @@ -90,7 +90,7 @@ srsran::srs_du::create_f1ap_ue_context_update_request(du_ue_index_t req.drbs_to_setup.back().five_qi = uint_to_five_qi(9); req.drbs_to_setup.back().uluptnl_info_list.resize(1); req.drbs_to_setup.back().uluptnl_info_list[0].gtp_teid = int_to_gtpu_teid(0); - req.drbs_to_setup.back().uluptnl_info_list[0].tp_address = transport_layer_address{"127.0.0.1"}; + req.drbs_to_setup.back().uluptnl_info_list[0].tp_address = transport_layer_address::create_from_string("127.0.0.1"); } return req; @@ -102,7 +102,7 @@ du_manager_test_bench::du_manager_test_bench(span cells) : du_mng_exec(worker), ue_exec_mapper(worker), cell_exec_mapper(worker), - params{{"srsgnb", 1, 1, {"127.0.0.1"}, du_cells}, + params{{"srsgnb", 1, 1, transport_layer_address::create_from_string("127.0.0.1"), du_cells}, {timers, du_mng_exec, ue_exec_mapper, cell_exec_mapper}, {f1ap, f1ap}, {f1u_gw}, diff --git a/tests/unittests/du_manager/du_ue/du_bearer_test.cpp b/tests/unittests/du_manager/du_ue/du_bearer_test.cpp index 935a2914ca..fe1e0c08a7 100644 --- a/tests/unittests/du_manager/du_ue/du_bearer_test.cpp +++ b/tests/unittests/du_manager/du_ue/du_bearer_test.cpp @@ -38,7 +38,7 @@ std::unique_ptr create_dummy_drb(drb_id_t drb_id, lcid_t lcid) static dummy_rlc_rlf_notifier rlf_notifier; std::array ul_tnls = { - up_transport_layer_info{transport_layer_address{"127.0.0.1"}, gtpu_teid_t{0}}}; + up_transport_layer_info{transport_layer_address::create_from_string("127.0.0.1"), gtpu_teid_t{0}}}; return create_drb(to_du_ue_index(0), to_du_cell_index(0), drb_id, 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 e81416446b..7008e6328a 100644 --- a/tests/unittests/du_manager/du_ue/ue_manager_test.cpp +++ b/tests/unittests/du_manager/du_ue/ue_manager_test.cpp @@ -96,7 +96,7 @@ class du_ue_manager_tester : public ::testing::Test null_rlc_pcap rlc_pcap; dummy_ue_resource_configurator_factory cell_res_alloc; - du_manager_params params{{"srsgnb", 1, 1, {"127.0.0.1"}, cells}, + du_manager_params params{{"srsgnb", 1, 1, transport_layer_address::create_from_string("127.0.0.1"), cells}, {timers, worker, ue_execs, cell_execs}, {f1ap_dummy, f1ap_dummy}, {f1u_dummy}, diff --git a/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp b/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp index 34289e4279..7c01e10951 100644 --- a/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp +++ b/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp @@ -93,7 +93,7 @@ e1ap_bearer_context_setup_request srsran::srs_cu_cp::generate_bearer_context_set res_to_setup_item.security_ind.integrity_protection_ind = integrity_protection_indication_t::not_needed; res_to_setup_item.security_ind.confidentiality_protection_ind = confidentiality_protection_indication_t::not_needed; res_to_setup_item.pdu_session_res_dl_ambr = 330000000; - res_to_setup_item.ng_ul_up_tnl_info = {transport_layer_address{"0.0.0.0"}, int_to_gtpu_teid(0)}; + res_to_setup_item.ng_ul_up_tnl_info = {transport_layer_address::create_from_string("0.0.0.0"), int_to_gtpu_teid(0)}; e1ap_drb_to_setup_item_ng_ran drb_to_setup_item; drb_to_setup_item.drb_id = uint_to_drb_id(1); diff --git a/tests/unittests/e1ap/common/test_helpers.h b/tests/unittests/e1ap/common/test_helpers.h index e1e6c7725a..a295a6bf10 100644 --- a/tests/unittests/e1ap/common/test_helpers.h +++ b/tests/unittests/e1ap/common/test_helpers.h @@ -75,7 +75,7 @@ class dummy_e1ap_cu_up_notifier : public srs_cu_up::e1ap_cu_up_notifier e1ap_pdu_session_resource_setup_modification_item response_setup_item; response_setup_item.pdu_session_id = request_setup_item.pdu_session_id; response_setup_item.ng_dl_up_tnl_info.gtp_teid = int_to_gtpu_teid(1); - response_setup_item.ng_dl_up_tnl_info.tp_address = transport_layer_address{"127.0.0.1"}; + response_setup_item.ng_dl_up_tnl_info.tp_address = transport_layer_address::create_from_string("127.0.0.1"); for (const auto& request_drb_item : request_setup_item.drb_to_setup_list_ng_ran) { e1ap_drb_setup_item_ng_ran response_drb_item; diff --git a/tests/unittests/f1ap/common/f1ap_asn1_helpers_test.cpp b/tests/unittests/f1ap/common/f1ap_asn1_helpers_test.cpp index 326df27738..a11019af4a 100644 --- a/tests/unittests/f1ap/common/f1ap_asn1_helpers_test.cpp +++ b/tests/unittests/f1ap/common/f1ap_asn1_helpers_test.cpp @@ -100,7 +100,7 @@ static uint32_t generate_gtp_teid() TEST(f1ap_asn1_helpers_test, test_up_transport_layer_converter) { - up_transport_layer_info up_tp_layer_info = {transport_layer_address{create_random_ipv4_string()}, + up_transport_layer_info up_tp_layer_info = {transport_layer_address::create_from_string(create_random_ipv4_string()), int_to_gtpu_teid(0x1)}; asn1::f1ap::up_transport_layer_info_c asn1_transport_layer_info; @@ -114,7 +114,7 @@ TEST(f1ap_asn1_helpers_test, test_up_transport_layer_converter) TEST(transport_layer_address_test, ipv6_transport_layer_address_to_asn1) { - up_transport_layer_info up_tp_layer_info = {transport_layer_address{create_random_ipv6_string()}, + up_transport_layer_info up_tp_layer_info = {transport_layer_address::create_from_string(create_random_ipv6_string()), int_to_gtpu_teid(0x1)}; asn1::f1ap::up_transport_layer_info_c asn1_transport_layer_info; diff --git a/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp b/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp index 409b293392..b8ec647b46 100644 --- a/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp +++ b/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp @@ -336,7 +336,8 @@ f1ap_ue_context_modification_request srsran::srs_cu_cp::generate_ue_context_modi drbs_to_be_setup_mod_item.qos_info.flows_mapped_to_drb_list.emplace(uint_to_qos_flow_id(1), flows_mapped_to_drb_item); // ul up tnl info to be setup list - up_transport_layer_info ul_up_tnl_info_item = {transport_layer_address{"127.0.0.1"}, int_to_gtpu_teid(1)}; + up_transport_layer_info ul_up_tnl_info_item = {transport_layer_address::create_from_string("127.0.0.1"), + int_to_gtpu_teid(1)}; drbs_to_be_setup_mod_item.ul_up_tnl_info_to_be_setup_list.push_back(ul_up_tnl_info_item); // rlc mode diff --git a/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp b/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp index 01f95054a1..73e06c273c 100644 --- a/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp +++ b/tests/unittests/f1ap/du/f1ap_du_test_helpers.cpp @@ -29,7 +29,7 @@ f1_setup_request_message srsran::srs_du::generate_f1_setup_request_message() ran_params.gnb_du_name = "srsgnb"; ran_params.gnb_du_id = 1; ran_params.rrc_version = 1; - ran_params.du_bind_addr = {"127.0.0.1"}; + ran_params.du_bind_addr = transport_layer_address::create_from_string("127.0.0.1"); du_cell_config cell = config_helpers::make_default_du_cell_config(); ran_params.cells = {cell}; fill_f1_setup_request(request_msg, ran_params); @@ -58,8 +58,8 @@ asn1::f1ap::drbs_to_be_setup_item_s srsran::srs_du::generate_drb_am_setup_item(d drb_info.snssai.sd.from_string("0027db"); drb.rlc_mode.value = rlc_mode_opts::rlc_am; drb.ul_up_tnl_info_to_be_setup_list.resize(1); - auto& gtp_tun = drb.ul_up_tnl_info_to_be_setup_list[0].ul_up_tnl_info.set_gtp_tunnel(); - transport_layer_address addr{"127.0.0.1"}; + auto& gtp_tun = drb.ul_up_tnl_info_to_be_setup_list[0].ul_up_tnl_info.set_gtp_tunnel(); + auto addr = transport_layer_address::create_from_string("127.0.0.1"); gtp_tun.transport_layer_address.from_string(addr.to_bitstring()); gtp_tun.gtp_teid.from_number(1); @@ -118,8 +118,8 @@ asn1::f1ap::drbs_to_be_setup_mod_item_s srsran::srs_du::generate_drb_am_mod_item drb_info.snssai.sd.from_string("0027db"); drb.rlc_mode.value = rlc_mode_opts::rlc_am; drb.ul_up_tnl_info_to_be_setup_list.resize(1); - auto& gtp_tun = drb.ul_up_tnl_info_to_be_setup_list[0].ul_up_tnl_info.set_gtp_tunnel(); - transport_layer_address addr{"127.0.0.1"}; + auto& gtp_tun = drb.ul_up_tnl_info_to_be_setup_list[0].ul_up_tnl_info.set_gtp_tunnel(); + auto addr = transport_layer_address::create_from_string("127.0.0.1"); gtp_tun.transport_layer_address.from_string(addr.to_bitstring()); gtp_tun.gtp_teid.from_number(1); return drb; 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 bccff11903..0442fecd4e 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 @@ -37,7 +37,7 @@ class f1ap_du_ue_context_modification_test : public f1ap_du_test drb.drb_id = drb_id; drb.dluptnl_info_list.resize(1); drb.dluptnl_info_list[0].gtp_teid = int_to_gtpu_teid(test_rgen::uniform_int()); - drb.dluptnl_info_list[0].tp_address = transport_layer_address{"127.0.0.1"}; + drb.dluptnl_info_list[0].tp_address = transport_layer_address::create_from_string("127.0.0.1"); } this->f1ap_du_cfg_handler.next_ue_context_update_response.du_to_cu_rrc_container = {0x1, 0x2, 0x3}; 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 059e858b77..fb63e7675f 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 @@ -72,7 +72,8 @@ class f1ap_du_ue_context_setup_test : public f1ap_du_test du_to_f1_resp.drbs_setup[i].drb_id = uint_to_drb_id(drb_id); du_to_f1_resp.drbs_setup[i].lcid = uint_to_lcid((uint8_t)LCID_MIN_DRB + drb_id); du_to_f1_resp.drbs_setup[i].dluptnl_info_list.resize(1); - du_to_f1_resp.drbs_setup[i].dluptnl_info_list[0] = up_transport_layer_info{{"127.0.0.1"}, int_to_gtpu_teid(1)}; + du_to_f1_resp.drbs_setup[i].dluptnl_info_list[0] = + up_transport_layer_info{transport_layer_address::create_from_string("127.0.0.1"), int_to_gtpu_teid(1)}; } } @@ -245,4 +246,4 @@ TEST_F(f1ap_du_test, f1ap_handles_precanned_ue_context_setup_request_correctly) // F1AP sends RRC Container present in UE CONTEXT SETUP REQUEST via SRB1. ASSERT_EQ(test_ues[ue_index].f1c_bearers[1].rx_sdu_notifier.last_pdu, ue_ctxt_setup_req.pdu.init_msg().value.ue_context_setup_request()->rrc_container); -} \ No newline at end of file +} diff --git a/tests/unittests/f1u/common/f1u_connector_test.cpp b/tests/unittests/f1u/common/f1u_connector_test.cpp index 44e6e525b3..cfefc24db2 100644 --- a/tests/unittests/f1u/common/f1u_connector_test.cpp +++ b/tests/unittests/f1u/common/f1u_connector_test.cpp @@ -114,8 +114,8 @@ TEST_F(f1u_connector_test, attach_detach_cu_up_f1u_to_du_f1u) f1u_cu_up_gateway* cu_gw = f1u_conn->get_f1u_cu_up_gateway(); srs_du::f1u_du_gateway* du_gw = f1u_conn->get_f1u_du_gateway(); - up_transport_layer_info ul_tnl{{"127.0.0.1"}, gtpu_teid_t{1}}; - up_transport_layer_info dl_tnl{{"127.0.0.2"}, gtpu_teid_t{2}}; + up_transport_layer_info ul_tnl{transport_layer_address::create_from_string("127.0.0.1"), gtpu_teid_t{1}}; + up_transport_layer_info dl_tnl{transport_layer_address::create_from_string("127.0.0.2"), gtpu_teid_t{2}}; // Create CU TX notifier adapter dummy_f1u_cu_up_rx_sdu_notifier cu_rx; @@ -164,8 +164,8 @@ TEST_F(f1u_connector_test, detach_du_f1u_first) f1u_cu_up_gateway* cu_gw = f1u_conn->get_f1u_cu_up_gateway(); srs_du::f1u_du_gateway* du_gw = f1u_conn->get_f1u_du_gateway(); - up_transport_layer_info ul_tnl{{"127.0.0.1"}, gtpu_teid_t{1}}; - up_transport_layer_info dl_tnl{{"127.0.0.2"}, gtpu_teid_t{2}}; + up_transport_layer_info ul_tnl{transport_layer_address::create_from_string("127.0.0.1"), gtpu_teid_t{1}}; + up_transport_layer_info dl_tnl{transport_layer_address::create_from_string("127.0.0.2"), gtpu_teid_t{2}}; // Create CU TX notifier adapter dummy_f1u_cu_up_rx_sdu_notifier cu_rx; @@ -214,9 +214,9 @@ TEST_F(f1u_connector_test, update_du_f1u) f1u_cu_up_gateway* cu_gw = f1u_conn->get_f1u_cu_up_gateway(); srs_du::f1u_du_gateway* du_gw = f1u_conn->get_f1u_du_gateway(); - up_transport_layer_info ul_tnl{{"127.0.0.1"}, gtpu_teid_t{1}}; - up_transport_layer_info dl_tnl1{{"127.0.0.2"}, gtpu_teid_t{2}}; - up_transport_layer_info dl_tnl2{{"127.0.0.3"}, gtpu_teid_t{2}}; + up_transport_layer_info ul_tnl{transport_layer_address::create_from_string("127.0.0.1"), gtpu_teid_t{1}}; + up_transport_layer_info dl_tnl1{transport_layer_address::create_from_string("127.0.0.2"), gtpu_teid_t{2}}; + up_transport_layer_info dl_tnl2{transport_layer_address::create_from_string("127.0.0.3"), gtpu_teid_t{2}}; // Create CU TX notifier adapter dummy_f1u_cu_up_rx_sdu_notifier cu_rx; diff --git a/tests/unittests/f1u/cu_up/f1u_cu_up_bearer_test.cpp b/tests/unittests/f1u/cu_up/f1u_cu_up_bearer_test.cpp index 31daa0914a..13a9a9299c 100644 --- a/tests/unittests/f1u/cu_up/f1u_cu_up_bearer_test.cpp +++ b/tests/unittests/f1u/cu_up/f1u_cu_up_bearer_test.cpp @@ -92,16 +92,18 @@ class f1u_cu_up_test : public ::testing::Test, public f1u_trx_test ue_inactivity_triggered = true; }); ue_inactivity_timer.run(); - f1u = std::make_unique(0, - drb_id, - up_transport_layer_info{{"127.0.0.1"}, gtpu_teid_t{ul_teid_next.value()++}}, - *tester, - *tester, - *tester, - ue_timer_factory, - ue_inactivity_timer, - ue_worker, - *tester); + f1u = std::make_unique( + 0, + drb_id, + up_transport_layer_info(transport_layer_address::create_from_string("127.0.0.1"), + gtpu_teid_t{ul_teid_next.value()++}), + *tester, + *tester, + *tester, + ue_timer_factory, + ue_inactivity_timer, + ue_worker, + *tester); } void TearDown() override diff --git a/tests/unittests/f1u/du/f1u_du_bearer_test.cpp b/tests/unittests/f1u/du/f1u_du_bearer_test.cpp index 1d1d090996..c96acc3257 100644 --- a/tests/unittests/f1u/du/f1u_du_bearer_test.cpp +++ b/tests/unittests/f1u/du/f1u_du_bearer_test.cpp @@ -69,13 +69,15 @@ class f1u_du_test : public ::testing::Test, public f1u_trx_test f1u_config config = {}; config.t_notify = f1u_ul_notif_time_ms; drb_id_t drb_id = drb_id_t::drb1; - f1u = std::make_unique(0, - drb_id, - up_transport_layer_info{{"127.0.0.1"}, gtpu_teid_t{dl_teid_next.value()++}}, - config, - *tester, - *tester, - timer_factory{timers, ue_worker}); + f1u = std::make_unique( + 0, + drb_id, + up_transport_layer_info{transport_layer_address::create_from_string("127.0.0.1"), + gtpu_teid_t{dl_teid_next.value()++}}, + config, + *tester, + *tester, + timer_factory{timers, ue_worker}); } void TearDown() override diff --git a/tests/unittests/ngap/ngap_test_messages.cpp b/tests/unittests/ngap/ngap_test_messages.cpp index 424441458b..76d4e2831f 100644 --- a/tests/unittests/ngap/ngap_test_messages.cpp +++ b/tests/unittests/ngap/ngap_test_messages.cpp @@ -455,7 +455,8 @@ srsran::srs_cu_cp::generate_cu_cp_pdu_session_resource_setup_response(pdu_sessio auto& dlqos_flow_per_tnl_info = pdu_session_setup_response_item.pdu_session_resource_setup_response_transfer.dlqos_flow_per_tnl_info; - dlqos_flow_per_tnl_info.up_tp_layer_info = {transport_layer_address{"0.0.0.0"}, int_to_gtpu_teid(0)}; + dlqos_flow_per_tnl_info.up_tp_layer_info = {transport_layer_address::create_from_string("0.0.0.0"), + int_to_gtpu_teid(0)}; cu_cp_associated_qos_flow assoc_qos_flow; assoc_qos_flow.qos_flow_id = uint_to_qos_flow_id(1); dlqos_flow_per_tnl_info.associated_qos_flow_list.emplace(uint_to_qos_flow_id(1), assoc_qos_flow); @@ -620,7 +621,8 @@ srsran::srs_cu_cp::generate_cu_cp_pdu_session_resource_modify_response(pdu_sessi pdu_session_modify_response_item.pdu_session_id = pdu_session_id; cu_cp_qos_flow_per_tnl_information qos_flow_per_tnl_info; - qos_flow_per_tnl_info.up_tp_layer_info = {transport_layer_address{"127.0.0.1"}, int_to_gtpu_teid(1)}; + qos_flow_per_tnl_info.up_tp_layer_info = {transport_layer_address::create_from_string("127.0.0.1"), + int_to_gtpu_teid(1)}; cu_cp_associated_qos_flow assoc_qos_flow; assoc_qos_flow.qos_flow_id = qos_flow_id; diff --git a/tests/unittests/ngap/ngap_validators_test.cpp b/tests/unittests/ngap/ngap_validators_test.cpp index c350973fb1..f04008dbf2 100644 --- a/tests/unittests/ngap/ngap_validators_test.cpp +++ b/tests/unittests/ngap/ngap_validators_test.cpp @@ -96,7 +96,7 @@ class ngap_validator_test : public ngap_test asn1::ngap::pdu_session_res_setup_request_transfer_s asn1_setup_req_transfer; asn1_setup_req_transfer->ul_ngu_up_tnl_info.set_gtp_tunnel(); - transport_layer_address addr{"127.0.0.1"}; + auto addr = transport_layer_address::create_from_string("127.0.0.1"); asn1_setup_req_transfer->ul_ngu_up_tnl_info.gtp_tunnel().transport_layer_address.from_string(addr.to_bitstring()); asn1_setup_req_transfer->ul_ngu_up_tnl_info.gtp_tunnel().gtp_teid.from_number(1); diff --git a/tests/unittests/support/network/transport_layer_address_test.cpp b/tests/unittests/support/network/transport_layer_address_test.cpp index 06d8221dd6..8c3e5b2a56 100644 --- a/tests/unittests/support/network/transport_layer_address_test.cpp +++ b/tests/unittests/support/network/transport_layer_address_test.cpp @@ -43,42 +43,45 @@ TEST(transport_layer_address_test, empty_address) TEST(transport_layer_address_test, conversion_to_ipv4_string) { - std::string ipv4_str = create_random_ipv4_string(); - transport_layer_address addr{ipv4_str}; + std::string ipv4_str = create_random_ipv4_string(); + auto addr = transport_layer_address::create_from_string(ipv4_str); ASSERT_EQ(addr.to_string(), ipv4_str); ASSERT_EQ(fmt::format("{}", addr), ipv4_str); } TEST(transport_layer_address_test, conversion_to_ipv6_string) { - std::string ipv6_str = create_random_ipv6_string(); - transport_layer_address addr{ipv6_str}; + std::string ipv6_str = create_random_ipv6_string(); + auto addr = transport_layer_address::create_from_string(ipv6_str); ASSERT_EQ(addr.to_string(), ipv6_str); ASSERT_EQ(fmt::format("{}", addr), ipv6_str); } TEST(transport_layer_address_test, ipv4_address_comparison) { - std::string ipv4_str1 = create_random_ipv4_string(); - std::string ipv4_str2 = create_random_ipv4_string(); - transport_layer_address addr1{ipv4_str1}, addr2{ipv4_str2}; + std::string ipv4_str1 = create_random_ipv4_string(); + std::string ipv4_str2 = create_random_ipv4_string(); + auto addr1 = transport_layer_address::create_from_string(ipv4_str1); + auto addr2 = transport_layer_address::create_from_string(ipv4_str2); ASSERT_EQ(addr1, ipv4_str1); ASSERT_EQ(addr2, ipv4_str2); } TEST(transport_layer_address_test, ipv6_address_comparison) { - std::string ipv6_str1 = create_random_ipv6_string(); - std::string ipv6_str2 = create_random_ipv6_string(); - transport_layer_address addr1{ipv6_str1}, addr2{ipv6_str2}; + std::string ipv6_str1 = create_random_ipv6_string(); + std::string ipv6_str2 = create_random_ipv6_string(); + auto addr1 = transport_layer_address::create_from_string(ipv6_str1); + auto addr2 = transport_layer_address::create_from_string(ipv6_str2); ASSERT_EQ(addr1, ipv6_str1); ASSERT_EQ(addr2, ipv6_str2); } TEST(transport_layer_address_test, ipv4_is_always_different_from_ipv6) { - std::string ipv4_str = create_random_ipv4_string(); - std::string ipv6_str = create_random_ipv6_string(); - transport_layer_address addr1{ipv4_str}, addr2{ipv6_str}; + std::string ipv4_str = create_random_ipv4_string(); + std::string ipv6_str = create_random_ipv6_string(); + auto addr1 = transport_layer_address::create_from_string(ipv4_str); + auto addr2 = transport_layer_address::create_from_string(ipv6_str); ASSERT_NE(addr1, addr2); } From 0a1ce0063c833810692683dc551da248f5c7f169 Mon Sep 17 00:00:00 2001 From: Pavel Harbanau Date: Wed, 6 Mar 2024 19:01:18 +0000 Subject: [PATCH 099/140] ofh: use symbols in top-level timing window parameters; add additional validation --- apps/gnb/gnb_appconfig.h | 16 +-- apps/gnb/gnb_appconfig_translators.cpp | 78 +++++++++---- apps/gnb/gnb_appconfig_validators.cpp | 31 +++++ .../srsran/ofh/ethernet/ethernet_frame_pool.h | 1 + include/srsran/ofh/ofh_sector_config.h | 4 +- .../ofh/receiver/ofh_receiver_configuration.h | 2 +- .../receiver/ofh_receiver_timing_parameters.h | 15 ++- .../ofh_transmitter_configuration.h | 31 +---- .../ofh_transmitter_timing_parameters.h | 43 +++++++ include/srsran/ru/ru_ofh_configuration.h | 4 +- lib/ofh/ofh_factories.cpp | 33 +++--- lib/ofh/receiver/ofh_rx_window_checker.cpp | 8 +- lib/ofh/receiver/ofh_rx_window_checker.h | 28 +---- lib/ofh/transmitter/helpers.h | 19 ++- .../ofh_downlink_handler_broadcast_impl.h | 2 +- .../transmitter/ofh_downlink_handler_impl.h | 2 +- .../ofh_message_transmitter_impl.cpp | 10 +- .../ofh_message_transmitter_impl.h | 40 +------ .../transmitter/ofh_transmitter_factories.cpp | 4 +- lib/ofh/transmitter/ofh_transmitter_impl.cpp | 2 +- .../ofh/ofh_integration_test.cpp | 30 +++-- .../ofh/ethernet/ethernet_frame_pool_test.cpp | 16 ++- .../receiver/ofh_rx_window_checker_test.cpp | 109 +++++++++--------- .../ofh_downlink_handler_impl_test.cpp | 12 +- 24 files changed, 296 insertions(+), 244 deletions(-) create mode 100644 include/srsran/ofh/transmitter/ofh_transmitter_timing_parameters.h diff --git a/apps/gnb/gnb_appconfig.h b/apps/gnb/gnb_appconfig.h index 7252ab01e1..ad2d8239a6 100644 --- a/apps/gnb/gnb_appconfig.h +++ b/apps/gnb/gnb_appconfig.h @@ -970,21 +970,21 @@ struct ru_ofh_base_cell_appconfig { /// Set this option when the operating bandwidth of the RU is larger than the configured bandwidth of the cell. optional ru_operating_bw; /// T1a maximum parameter for downlink Control-Plane in microseconds. - unsigned T1a_max_cp_dl = 500U; + std::chrono::microseconds T1a_max_cp_dl{500}; /// T1a minimum parameter for downlink Control-Plane in microseconds. - unsigned T1a_min_cp_dl = 258U; + std::chrono::microseconds T1a_min_cp_dl{258}; /// T1a maximum parameter for uplink Control-Plane in microseconds. - unsigned T1a_max_cp_ul = 500U; + std::chrono::microseconds T1a_max_cp_ul{500}; /// T1a minimum parameter for uplink Control-Plane in microseconds. - unsigned T1a_min_cp_ul = 285U; + std::chrono::microseconds T1a_min_cp_ul{285}; /// T1a maximum parameter for downlink User-Plane in microseconds. - unsigned T1a_max_up = 300U; + std::chrono::microseconds T1a_max_up{300}; /// T1a minimum parameter for downlink User-Plane in microseconds. - unsigned T1a_min_up = 85U; + std::chrono::microseconds T1a_min_up{85}; /// Ta4 maximum parameter for uplink User-Plane in microseconds. - unsigned Ta4_max = 300U; + std::chrono::microseconds Ta4_max{300}; /// Ta4 minimum parameter for uplink User-Plane in microseconds. - unsigned Ta4_min = 85U; + std::chrono::microseconds Ta4_min{85}; /// Enables the Control-Plane PRACH message signalling. bool is_prach_control_plane_enabled = true; /// \brief Downlink broadcast flag. diff --git a/apps/gnb/gnb_appconfig_translators.cpp b/apps/gnb/gnb_appconfig_translators.cpp index 7377ef635b..605709cc43 100644 --- a/apps/gnb/gnb_appconfig_translators.cpp +++ b/apps/gnb/gnb_appconfig_translators.cpp @@ -1439,6 +1439,40 @@ static bool parse_mac_address(const std::string& mac_str, span mac) return true; } +/// Converts reception window timing parameters from microseconds to number of symbols given the symbol duration. +static ofh::rx_window_timing_parameters +rx_timing_window_params_us_to_symbols(std::chrono::microseconds Ta4_max, + std::chrono::microseconds Ta4_min, + std::chrono::duration symbol_duration) +{ + ofh::rx_window_timing_parameters rx_window_timing_params; + rx_window_timing_params.sym_start = std::ceil(Ta4_min / symbol_duration); + rx_window_timing_params.sym_end = std::ceil(Ta4_max / symbol_duration); + + return rx_window_timing_params; +} + +/// Converts transmission window timing parameters from microseconds to number of symbols given the symbol duration. +static ofh::tx_window_timing_parameters +tx_timing_window_params_us_to_symbols(std::chrono::microseconds T1a_max_cp_dl, + std::chrono::microseconds T1a_min_cp_dl, + std::chrono::microseconds T1a_max_cp_ul, + std::chrono::microseconds T1a_min_cp_ul, + std::chrono::microseconds T1a_max_up, + std::chrono::microseconds T1a_min_up, + std::chrono::duration symbol_duration) +{ + ofh::tx_window_timing_parameters tx_window_timing_params; + tx_window_timing_params.sym_cp_dl_start = std::floor(T1a_max_cp_dl / symbol_duration); + tx_window_timing_params.sym_cp_dl_end = std::ceil(T1a_min_cp_dl / symbol_duration); + tx_window_timing_params.sym_cp_ul_start = std::floor(T1a_max_cp_ul / symbol_duration); + tx_window_timing_params.sym_cp_ul_end = std::ceil(T1a_min_cp_ul / symbol_duration); + tx_window_timing_params.sym_up_dl_start = std::floor(T1a_max_up / symbol_duration); + tx_window_timing_params.sym_up_dl_end = std::ceil(T1a_min_up / symbol_duration); + + return tx_window_timing_params; +} + static void generate_ru_ofh_config(ru_ofh_configuration& out_cfg, const gnb_appconfig& config, span du_cells) { @@ -1472,6 +1506,9 @@ generate_ru_ofh_config(ru_ofh_configuration& out_cfg, const gnb_appconfig& confi srsran_terminate("Invalid Radio Unit MAC address"); } + std::chrono::duration symbol_duration( + (1e6 / (get_nsymb_per_slot(cyclic_prefix::NORMAL) * get_nof_slots_per_subframe(cell.common_scs)))); + sector_cfg.cp = cyclic_prefix::NORMAL; sector_cfg.scs = cell.common_scs; sector_cfg.bw = cell.channel_bw_mhz; @@ -1479,26 +1516,27 @@ generate_ru_ofh_config(ru_ofh_configuration& out_cfg, const gnb_appconfig& confi sector_cfg.ru_operating_bw = cell_cfg.cell.ru_operating_bw; sector_cfg.is_uplink_static_comp_hdr_enabled = cell_cfg.cell.is_uplink_static_comp_hdr_enabled; sector_cfg.is_downlink_static_comp_hdr_enabled = cell_cfg.cell.is_downlink_static_comp_hdr_enabled; - sector_cfg.tx_window_timing_params = {std::chrono::microseconds(cell_cfg.cell.T1a_max_cp_dl), - std::chrono::microseconds(cell_cfg.cell.T1a_min_cp_dl), - std::chrono::microseconds(cell_cfg.cell.T1a_max_cp_ul), - std::chrono::microseconds(cell_cfg.cell.T1a_min_cp_ul), - std::chrono::microseconds(cell_cfg.cell.T1a_max_up), - std::chrono::microseconds(cell_cfg.cell.T1a_min_up)}; - sector_cfg.rx_window_timing_params = {std::chrono::microseconds(cell_cfg.cell.Ta4_max), - std::chrono::microseconds(cell_cfg.cell.Ta4_min)}; - sector_cfg.is_prach_control_plane_enabled = cell_cfg.cell.is_prach_control_plane_enabled; - sector_cfg.is_downlink_broadcast_enabled = cell_cfg.cell.is_downlink_broadcast_enabled; - sector_cfg.ignore_ecpri_payload_size_field = cell_cfg.cell.ignore_ecpri_payload_size_field; - sector_cfg.ignore_ecpri_seq_id_field = cell_cfg.cell.ignore_ecpri_seq_id_field; - sector_cfg.warn_unreceived_ru_frames = cell_cfg.cell.warn_unreceived_ru_frames; - sector_cfg.ul_compression_params = {ofh::to_compression_type(cell_cfg.cell.compression_method_ul), - cell_cfg.cell.compression_bitwidth_ul}; - sector_cfg.dl_compression_params = {ofh::to_compression_type(cell_cfg.cell.compression_method_dl), - cell_cfg.cell.compression_bitwidth_dl}; - sector_cfg.prach_compression_params = {ofh::to_compression_type(cell_cfg.cell.compression_method_prach), - cell_cfg.cell.compression_bitwidth_prach}; - sector_cfg.iq_scaling = cell_cfg.cell.iq_scaling; + sector_cfg.tx_window_timing_params = tx_timing_window_params_us_to_symbols(cell_cfg.cell.T1a_max_cp_dl, + cell_cfg.cell.T1a_min_cp_dl, + cell_cfg.cell.T1a_max_cp_ul, + cell_cfg.cell.T1a_min_cp_ul, + cell_cfg.cell.T1a_max_up, + cell_cfg.cell.T1a_min_up, + symbol_duration); + sector_cfg.rx_window_timing_params = + rx_timing_window_params_us_to_symbols(cell_cfg.cell.Ta4_max, cell_cfg.cell.Ta4_min, symbol_duration); + sector_cfg.is_prach_control_plane_enabled = cell_cfg.cell.is_prach_control_plane_enabled; + sector_cfg.is_downlink_broadcast_enabled = cell_cfg.cell.is_downlink_broadcast_enabled; + sector_cfg.ignore_ecpri_payload_size_field = cell_cfg.cell.ignore_ecpri_payload_size_field; + sector_cfg.ignore_ecpri_seq_id_field = cell_cfg.cell.ignore_ecpri_seq_id_field; + sector_cfg.warn_unreceived_ru_frames = cell_cfg.cell.warn_unreceived_ru_frames; + sector_cfg.ul_compression_params = {ofh::to_compression_type(cell_cfg.cell.compression_method_ul), + cell_cfg.cell.compression_bitwidth_ul}; + sector_cfg.dl_compression_params = {ofh::to_compression_type(cell_cfg.cell.compression_method_dl), + cell_cfg.cell.compression_bitwidth_dl}; + sector_cfg.prach_compression_params = {ofh::to_compression_type(cell_cfg.cell.compression_method_prach), + cell_cfg.cell.compression_bitwidth_prach}; + sector_cfg.iq_scaling = cell_cfg.cell.iq_scaling; sector_cfg.tci = cell_cfg.vlan_tag; sector_cfg.prach_eaxc.assign(cell_cfg.ru_prach_port_id.begin(), cell_cfg.ru_prach_port_id.end()); diff --git a/apps/gnb/gnb_appconfig_validators.cpp b/apps/gnb/gnb_appconfig_validators.cpp index 391d22a6c5..6652bcc87f 100644 --- a/apps/gnb/gnb_appconfig_validators.cpp +++ b/apps/gnb/gnb_appconfig_validators.cpp @@ -129,6 +129,13 @@ template return std::unique(temp_ports.begin(), temp_ports.end()) == temp_ports.end(); } +static bool validate_transmission_window(std::chrono::duration symbol_duration, + std::chrono::microseconds window_start, + std::chrono::microseconds window_end) +{ + return ((window_end - window_start) > symbol_duration); +} + /// Validates the given Open Fronthaul Radio Unit application configuration. Returns true on success, otherwise /// false. static bool validate_ru_ofh_appconfig(const gnb_appconfig& config) @@ -139,6 +146,30 @@ static bool validate_ru_ofh_appconfig(const gnb_appconfig& config) const ru_ofh_cell_appconfig& ofh_cell = ofh_cfg.cells[i]; const base_cell_appconfig& cell_cfg = config.cells_cfg[i].cell; + const std::chrono::duration symbol_duration( + (1e3 / (get_nsymb_per_slot(cyclic_prefix::NORMAL) * get_nof_slots_per_subframe(cell_cfg.common_scs)))); + + if (!validate_transmission_window(symbol_duration, ofh_cell.cell.T1a_min_cp_dl, ofh_cell.cell.T1a_max_cp_dl)) { + fmt::print("Transmission timing window length for DL Control-Plane must be bigger than the symbol duration " + "({:.2f}us).\n", + symbol_duration.count()); + return false; + } + + if (!validate_transmission_window(symbol_duration, ofh_cell.cell.T1a_min_cp_ul, ofh_cell.cell.T1a_max_cp_ul)) { + fmt::print("Transmission timing window length for UL Control-Plane must be bigger than the symbol duration " + "({:.2f}us).\n", + symbol_duration.count()); + return false; + } + + if (!validate_transmission_window(symbol_duration, ofh_cell.cell.T1a_min_up, ofh_cell.cell.T1a_max_up)) { + fmt::print( + "Transmission timing window length for DL User-Plane must be bigger than the symbol duration ({:.2f}us).\n", + symbol_duration.count()); + return false; + } + if (!ofh_cell.cell.is_downlink_broadcast_enabled && cell_cfg.nof_antennas_dl != ofh_cell.ru_dl_port_id.size()) { fmt::print("RU number of downlink ports={} must match the number of transmission antennas={}\n", ofh_cell.ru_dl_port_id.size(), diff --git a/include/srsran/ofh/ethernet/ethernet_frame_pool.h b/include/srsran/ofh/ethernet/ethernet_frame_pool.h index 59349f0008..883b6186bc 100644 --- a/include/srsran/ofh/ethernet/ethernet_frame_pool.h +++ b/include/srsran/ofh/ethernet/ethernet_frame_pool.h @@ -175,6 +175,7 @@ class frame_buffer_array buffer.status = frame_buffer::frame_buffer_status::free; } } + used_buffers.clear(); } // Returns a vector of pointers to the buffers ready for sending. diff --git a/include/srsran/ofh/ofh_sector_config.h b/include/srsran/ofh/ofh_sector_config.h index 68a5bed338..43cd8ab83d 100644 --- a/include/srsran/ofh/ofh_sector_config.h +++ b/include/srsran/ofh/ofh_sector_config.h @@ -46,9 +46,9 @@ struct sector_configuration { uint16_t tci; /// DU transmission window timing parameters. - du_tx_window_timing_parameters tx_window_timing_params; + tx_window_timing_parameters tx_window_timing_params; /// Reception window timing parameters. - du_rx_window_timing_parameters rx_window_timing_params; + rx_window_timing_parameters rx_window_timing_params; /// Cyclic prefix. cyclic_prefix cp; diff --git a/include/srsran/ofh/receiver/ofh_receiver_configuration.h b/include/srsran/ofh/receiver/ofh_receiver_configuration.h index 5ff460d79a..cc894529f8 100644 --- a/include/srsran/ofh/receiver/ofh_receiver_configuration.h +++ b/include/srsran/ofh/receiver/ofh_receiver_configuration.h @@ -39,7 +39,7 @@ struct receiver_config { /// Tag control information field. uint16_t tci; /// Reception window timing parameters. - du_rx_window_timing_parameters rx_timing_params; + rx_window_timing_parameters rx_timing_params; /// \brief RU operating bandwidth. /// /// Set this option when the operating bandwidth of the RU is larger than the configured bandwidth of the cell. diff --git a/include/srsran/ofh/receiver/ofh_receiver_timing_parameters.h b/include/srsran/ofh/receiver/ofh_receiver_timing_parameters.h index b3540a95e2..ea9e464bec 100644 --- a/include/srsran/ofh/receiver/ofh_receiver_timing_parameters.h +++ b/include/srsran/ofh/receiver/ofh_receiver_timing_parameters.h @@ -11,16 +11,19 @@ #pragma once #include +#include namespace srsran { namespace ofh { -/// \brief Structure storing the reception window timing parameters. -struct du_rx_window_timing_parameters { - /// Offset from the current OTA symbol to the end of UL User-Plane reception window. - std::chrono::microseconds Ta4_max; - /// Offset from the current OTA symbol to the start of UL User-Plane reception window. - std::chrono::microseconds Ta4_min; +/// \brief Structure storing the reception window timing parameters expressed in a number of symbols. +struct rx_window_timing_parameters { + /// Offset from the current OTA symbol to the first symbol at which UL User-Plane message can be received within its + /// reception window. Must be calculated based on \c Ta4_min parameter. + unsigned sym_start; + /// Offset from the current OTA symbol to the last symbol at which UL User-Plane message can be received within its + /// reception window. Must be calculated based on \c Ta4_max parameter. + unsigned sym_end; }; } // namespace ofh diff --git a/include/srsran/ofh/transmitter/ofh_transmitter_configuration.h b/include/srsran/ofh/transmitter/ofh_transmitter_configuration.h index 1aa5229edc..7671abc0e9 100644 --- a/include/srsran/ofh/transmitter/ofh_transmitter_configuration.h +++ b/include/srsran/ofh/transmitter/ofh_transmitter_configuration.h @@ -19,6 +19,7 @@ #include "srsran/ofh/ofh_constants.h" #include "srsran/ofh/serdes/ofh_cplane_message_builder.h" #include "srsran/ofh/serdes/ofh_uplane_message_builder.h" +#include "srsran/ofh/transmitter/ofh_transmitter_timing_parameters.h" #include "srsran/ran/bs_channel_bandwidth.h" #include "srsran/ran/cyclic_prefix.h" #include "srsran/ran/tdd/tdd_ul_dl_config.h" @@ -26,32 +27,6 @@ namespace srsran { namespace ofh { -/// \brief Structure storing the transmission window timing parameters. -struct du_tx_window_timing_parameters { - /// Offset from the current OTA symbol to the start of DL Control-Plane transmission window. - std::chrono::microseconds T1a_max_cp_dl; - /// Offset from the current OTA symbol to the end of DL Control-Plane transmission window. - std::chrono::microseconds T1a_min_cp_dl; - /// Offset from the current OTA symbol to the start of UL Control-Plane transmission window. - std::chrono::microseconds T1a_max_cp_ul; - /// Offset from the current OTA symbol to the end of UL Control-Plane transmission window. - std::chrono::microseconds T1a_min_cp_ul; - /// Offset from the current OTA symbol to the start of DL User-Plane transmission window. - std::chrono::microseconds T1a_max_up; - /// Offset from the current OTA symbol to the end of DL User-Plane transmission window. - std::chrono::microseconds T1a_min_up; -}; - -/// Configuration used by ofh_symbol_handler implementations. -struct symbol_handler_config { - /// Transmission window timing parameters for delay management. - du_tx_window_timing_parameters tx_timing_params; - /// Number of symbols per slot. - unsigned symbols_per_slot; - /// Highest subcarrier spacing. - subcarrier_spacing scs; -}; - /// Open Fronthaul transmitter configuration. struct transmitter_config { /// Radio sector identifier. @@ -62,6 +37,8 @@ struct transmitter_config { subcarrier_spacing scs; /// Cyclic prefix. cyclic_prefix cp; + /// Transmission window timing parameters. + tx_window_timing_parameters tx_timing_params; /// Downlink eAxC. static_vector dl_eaxc; /// Uplink eAxC. @@ -84,8 +61,6 @@ struct transmitter_config { units::bytes mtu_size; /// RU working bandwidth. bs_channel_bandwidth_fr1 ru_working_bw; - /// Open Fronthaul symbol handler configuration. - symbol_handler_config symbol_handler_cfg; /// Downlink compression parameters. ru_compression_params dl_compr_params; /// Uplink compression parameters. diff --git a/include/srsran/ofh/transmitter/ofh_transmitter_timing_parameters.h b/include/srsran/ofh/transmitter/ofh_transmitter_timing_parameters.h new file mode 100644 index 0000000000..7c108fea66 --- /dev/null +++ b/include/srsran/ofh/transmitter/ofh_transmitter_timing_parameters.h @@ -0,0 +1,43 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +#include +#include + +namespace srsran { +namespace ofh { + +/// Structure storing the transmission window timing parameters expressed in a number of symbols. +struct tx_window_timing_parameters { + /// Offset from the current OTA symbol to the first symbol at which DL Control-Plane message can be sent, or in + /// other words it is the offset to the start of DL Control-Plane transmission window. Must be calculated based on + /// \c T1a_max_cp_dl parameter. + unsigned sym_cp_dl_start; + /// Offset from the current OTA symbol to the last symbol at which DL Control-Plane message can be sent within its + /// transmission window. Must be calculated based on \c T1a_min_cp_dl parameter. + unsigned sym_cp_dl_end; + /// Offset from the current OTA symbol to the first symbol at which UL Control-Plane message can be sent within its + /// transmission window. Must be calculated based on \c T1a_max_cp_ul parameter. + unsigned sym_cp_ul_start; + /// Offset from the current OTA symbol to the last symbol at which UL Control-Plane message can be sent within its + /// transmission window. Must be calculated based on \c T1a_min_cp_ul parameter. + unsigned sym_cp_ul_end; + /// Offset from the current OTA symbol to the first symbol at which DL User-Plane message can be sent within its + /// transmission window. Must be calculated based on \c T1a_max_up parameter. + unsigned sym_up_dl_start; + /// Offset from the current OTA symbol to the last symbol at which DL User-Plane message can be sent within its + /// transmission window. Must be calculated based on \c T1a_min_up parameter. + unsigned sym_up_dl_end; +}; + +} // namespace ofh +} // namespace srsran diff --git a/include/srsran/ru/ru_ofh_configuration.h b/include/srsran/ru/ru_ofh_configuration.h index 97b876d33a..5cdd3c6d41 100644 --- a/include/srsran/ru/ru_ofh_configuration.h +++ b/include/srsran/ru/ru_ofh_configuration.h @@ -35,9 +35,9 @@ struct ru_ofh_sector_configuration { optional ru_operating_bw; /// DU transmission window timing parameters. - ofh::du_tx_window_timing_parameters tx_window_timing_params; + ofh::tx_window_timing_parameters tx_window_timing_params; /// Reception window timing parameters. - ofh::du_rx_window_timing_parameters rx_window_timing_params; + ofh::rx_window_timing_parameters rx_window_timing_params; /// Enables the Control-Plane PRACH message signalling. bool is_prach_control_plane_enabled = false; diff --git a/lib/ofh/ofh_factories.cpp b/lib/ofh/ofh_factories.cpp index 96e03e304a..6507e6a429 100644 --- a/lib/ofh/ofh_factories.cpp +++ b/lib/ofh/ofh_factories.cpp @@ -61,23 +61,22 @@ static transmitter_config generate_transmitter_config(const sector_configuration { transmitter_config tx_config; - tx_config.sector = sector_cfg.sector_id; - tx_config.bw = sector_cfg.bw; - tx_config.scs = sector_cfg.scs; - tx_config.cp = sector_cfg.cp; - tx_config.dl_eaxc = sector_cfg.dl_eaxc; - tx_config.ul_eaxc = sector_cfg.ul_eaxc; - tx_config.prach_eaxc = sector_cfg.prach_eaxc; - tx_config.is_prach_cp_enabled = sector_cfg.is_prach_control_plane_enabled; - tx_config.mac_dst_address = sector_cfg.mac_dst_address; - tx_config.mac_src_address = sector_cfg.mac_src_address; - tx_config.tci = sector_cfg.tci; - tx_config.interface = sector_cfg.interface; - tx_config.is_promiscuous_mode_enabled = sector_cfg.is_promiscuous_mode_enabled; - tx_config.mtu_size = sector_cfg.mtu_size; - tx_config.ru_working_bw = sector_cfg.ru_operating_bw; - tx_config.symbol_handler_cfg = { - sector_cfg.tx_window_timing_params, get_nsymb_per_slot(sector_cfg.cp), sector_cfg.scs}; + tx_config.sector = sector_cfg.sector_id; + tx_config.bw = sector_cfg.bw; + tx_config.scs = sector_cfg.scs; + tx_config.cp = sector_cfg.cp; + tx_config.dl_eaxc = sector_cfg.dl_eaxc; + tx_config.ul_eaxc = sector_cfg.ul_eaxc; + tx_config.prach_eaxc = sector_cfg.prach_eaxc; + tx_config.is_prach_cp_enabled = sector_cfg.is_prach_control_plane_enabled; + tx_config.mac_dst_address = sector_cfg.mac_dst_address; + tx_config.mac_src_address = sector_cfg.mac_src_address; + tx_config.tci = sector_cfg.tci; + tx_config.interface = sector_cfg.interface; + tx_config.is_promiscuous_mode_enabled = sector_cfg.is_promiscuous_mode_enabled; + tx_config.mtu_size = sector_cfg.mtu_size; + tx_config.ru_working_bw = sector_cfg.ru_operating_bw; + tx_config.tx_timing_params = sector_cfg.tx_window_timing_params; tx_config.dl_compr_params = sector_cfg.dl_compression_params; tx_config.ul_compr_params = sector_cfg.ul_compression_params; tx_config.prach_compr_params = sector_cfg.prach_compression_params; diff --git a/lib/ofh/receiver/ofh_rx_window_checker.cpp b/lib/ofh/receiver/ofh_rx_window_checker.cpp index 64d519a05d..8b940b9c47 100644 --- a/lib/ofh/receiver/ofh_rx_window_checker.cpp +++ b/lib/ofh/receiver/ofh_rx_window_checker.cpp @@ -16,9 +16,9 @@ using namespace ofh; static constexpr unsigned OFH_MAX_NOF_SFN = 256U; rx_window_checker::rx_window_checker(srslog::basic_logger& logger_, - const du_rx_window_timing_parameters& params, + const rx_window_timing_parameters& params, std::chrono::duration symbol_duration) : - timing_parameters(params, symbol_duration), + timing_parameters(params), nof_symbols_in_one_second(std::ceil(std::chrono::seconds(1) / symbol_duration)), nof_symbols(0), statistics(logger_) @@ -80,14 +80,14 @@ bool rx_window_checker::update_rx_window_statistics(slot_symbol_point symbol_poi int diff = calculate_slot_symbol_point_distance(ota_point, symbol_point); // Late detected. - if (diff > timing_parameters.sym_end) { + if (diff > static_cast(timing_parameters.sym_end)) { statistics.increment_late_counter(); return false; } // Early detected. - if (diff < timing_parameters.sym_start) { + if (diff < static_cast(timing_parameters.sym_start)) { statistics.increment_early_counter(); return false; diff --git a/lib/ofh/receiver/ofh_rx_window_checker.h b/lib/ofh/receiver/ofh_rx_window_checker.h index 9f0755eaa8..df63de9059 100644 --- a/lib/ofh/receiver/ofh_rx_window_checker.h +++ b/lib/ofh/receiver/ofh_rx_window_checker.h @@ -53,25 +53,9 @@ class rx_window_checker : public ota_symbol_boundary_notifier uint64_t nof_late_messages() const { return late_counter.load(std::memory_order_relaxed); } }; - /// Reception window timing parameters. - struct rx_timing_parameters { - /// Offset from the current OTA symbol to the first symbol at which UL User-Plane message can be received within its - /// reception window. Must be calculated based on \c Ta4_min parameter. - int sym_start; - /// Offset from the current OTA symbol to the last symbol at which UL User-Plane message can be received within its - /// reception window. Must be calculated based on \c Ta4_max parameter. - int sym_end; - - rx_timing_parameters(const du_rx_window_timing_parameters& params, - std::chrono::duration symbol_duration) : - sym_start(std::ceil(params.Ta4_min / symbol_duration)), sym_end(std::floor(params.Ta4_max / symbol_duration)) - { - } - }; - public: rx_window_checker(srslog::basic_logger& logger_, - const du_rx_window_timing_parameters& params, + const rx_window_timing_parameters& params, std::chrono::duration symbol_duration); // See interface for documentation. @@ -90,11 +74,11 @@ class rx_window_checker : public ota_symbol_boundary_notifier void print_statistics(); private: - const rx_timing_parameters timing_parameters; - const unsigned nof_symbols_in_one_second; - unsigned nof_symbols; - rx_window_checker_statistics statistics; - std::atomic count_val; + const rx_window_timing_parameters timing_parameters; + const unsigned nof_symbols_in_one_second; + unsigned nof_symbols; + rx_window_checker_statistics statistics; + std::atomic count_val; }; } // namespace ofh diff --git a/lib/ofh/transmitter/helpers.h b/lib/ofh/transmitter/helpers.h index c8faf46f57..f1e002fc1d 100644 --- a/lib/ofh/transmitter/helpers.h +++ b/lib/ofh/transmitter/helpers.h @@ -18,28 +18,23 @@ namespace srsran { namespace ofh { /// Returns the maximum value between the minimum T1a values in symbol units. -inline unsigned -get_biggest_min_tx_parameter_in_symbols(const du_tx_window_timing_parameters& tx_timing_params, - const std::chrono::duration& symbol_duration_ns) +inline unsigned get_biggest_min_tx_parameter(const tx_window_timing_parameters& tx_timing_params) { - auto max_value = - std::max({tx_timing_params.T1a_min_cp_dl, tx_timing_params.T1a_min_cp_ul, tx_timing_params.T1a_min_up}); - - return std::floor(max_value / symbol_duration_ns); + return std::max({tx_timing_params.sym_cp_dl_end, tx_timing_params.sym_cp_ul_end, tx_timing_params.sym_up_dl_end}); } /// Returns duration of the OFH downlink processing plus the transmission window in symbol units. -inline unsigned calculate_nof_symbols_before_ota(cyclic_prefix cp, - subcarrier_spacing scs, - std::chrono::microseconds dl_processing_time, - const du_tx_window_timing_parameters tx_timing_params) +inline unsigned calculate_nof_symbols_before_ota(cyclic_prefix cp, + subcarrier_spacing scs, + std::chrono::microseconds dl_processing_time, + const tx_window_timing_parameters tx_timing_params) { unsigned nof_symbols = get_nsymb_per_slot(cp); auto symbol_duration_ns = std::chrono::duration(1e6 / (nof_symbols * get_nof_slots_per_subframe(scs))); unsigned dl_processing_time_in_symbols = std::floor(dl_processing_time / symbol_duration_ns); - return dl_processing_time_in_symbols + get_biggest_min_tx_parameter_in_symbols(tx_timing_params, symbol_duration_ns); + return dl_processing_time_in_symbols + get_biggest_min_tx_parameter(tx_timing_params); } } // namespace ofh diff --git a/lib/ofh/transmitter/ofh_downlink_handler_broadcast_impl.h b/lib/ofh/transmitter/ofh_downlink_handler_broadcast_impl.h index a42e4c1c63..4b02fc371d 100644 --- a/lib/ofh/transmitter/ofh_downlink_handler_broadcast_impl.h +++ b/lib/ofh/transmitter/ofh_downlink_handler_broadcast_impl.h @@ -39,7 +39,7 @@ struct downlink_handler_broadcast_impl_config { /// Downlink processing time in microseconds. std::chrono::microseconds dl_processing_time; /// Transmission window timing parameters for delay management. - du_tx_window_timing_parameters tx_timing_params; + tx_window_timing_parameters tx_timing_params; }; /// Downlink handler broadcast implementation dependencies. diff --git a/lib/ofh/transmitter/ofh_downlink_handler_impl.h b/lib/ofh/transmitter/ofh_downlink_handler_impl.h index 20a1843ed7..2a563995c3 100644 --- a/lib/ofh/transmitter/ofh_downlink_handler_impl.h +++ b/lib/ofh/transmitter/ofh_downlink_handler_impl.h @@ -39,7 +39,7 @@ struct downlink_handler_impl_config { /// Downlink processing time in microseconds. std::chrono::microseconds dl_processing_time; /// Transmission window timing parameters for delay management. - du_tx_window_timing_parameters tx_timing_params; + tx_window_timing_parameters tx_timing_params; }; /// Downlink handler implementation dependencies. diff --git a/lib/ofh/transmitter/ofh_message_transmitter_impl.cpp b/lib/ofh/transmitter/ofh_message_transmitter_impl.cpp index e357933666..347c598532 100644 --- a/lib/ofh/transmitter/ofh_message_transmitter_impl.cpp +++ b/lib/ofh/transmitter/ofh_message_transmitter_impl.cpp @@ -15,16 +15,10 @@ using namespace srsran; using namespace ofh; message_transmitter_impl::message_transmitter_impl(srslog::basic_logger& logger_, - const symbol_handler_config& cfg, + const tx_window_timing_parameters& timing_params_, std::unique_ptr gw, std::shared_ptr frame_pool) : - logger(logger_), - pool_ptr(frame_pool), - pool(*pool_ptr), - gateway(std::move(gw)), - timing_params( - cfg.tx_timing_params, - std::chrono::duration(1e6 / (cfg.symbols_per_slot * get_nof_slots_per_subframe(cfg.scs)))) + logger(logger_), pool_ptr(frame_pool), pool(*pool_ptr), gateway(std::move(gw)), timing_params(timing_params_) { srsran_assert(gateway, "Invalid Ethernet gateway"); srsran_assert(pool_ptr, "Invalid frame pool"); diff --git a/lib/ofh/transmitter/ofh_message_transmitter_impl.h b/lib/ofh/transmitter/ofh_message_transmitter_impl.h index 08b662261e..b127119b3d 100644 --- a/lib/ofh/transmitter/ofh_message_transmitter_impl.h +++ b/lib/ofh/transmitter/ofh_message_transmitter_impl.h @@ -13,7 +13,7 @@ #include "srsran/ofh/ethernet/ethernet_frame_pool.h" #include "srsran/ofh/ethernet/ethernet_gateway.h" #include "srsran/ofh/timing/ofh_ota_symbol_boundary_notifier.h" -#include "srsran/ofh/transmitter/ofh_transmitter_configuration.h" +#include "srsran/ofh/transmitter/ofh_transmitter_timing_parameters.h" namespace srsran { namespace ofh { @@ -26,40 +26,6 @@ class message_transmitter_impl : public ota_symbol_boundary_notifier /// Maximum number of frames allowed to be transmitted in a single burst. static constexpr unsigned MAX_BURST_SIZE = 64; - /// Internal structure used to store transmission window timing parameters expressed in a number of symbols. - struct tx_timing_parameters { - /// Offset from the current OTA symbol to the first symbol at which DL Control-Plane message can be sent, or in - /// other words it is the offset to the start of DL Control-Plane transmission window. Must be calculated based on - /// \c T1a_max_cp_dl parameter. - unsigned sym_cp_dl_start; - /// Offset from the current OTA symbol to the last symbol at which DL Control-Plane message can be sent within its - /// transmission window. Must be calculated based on \c T1a_min_cp_dl parameter. - unsigned sym_cp_dl_end; - /// Offset from the current OTA symbol to the first symbol at which UL Control-Plane message can be sent within its - /// transmission window. Must be calculated based on \c T1a_max_cp_ul parameter. - unsigned sym_cp_ul_start; - /// Offset from the current OTA symbol to the last symbol at which UL Control-Plane message can be sent within its - /// transmission window. Must be calculated based on \c T1a_min_cp_ul parameter. - unsigned sym_cp_ul_end; - /// Offset from the current OTA symbol to the first symbol at which DL User-Plane message can be sent within its - /// transmission window. Must be calculated based on \c T1a_max_up parameter. - unsigned sym_up_dl_start; - /// Offset from the current OTA symbol to the last symbol at which DL User-Plane message can be sent within its - /// transmission window. Must be calculated based on \c T1a_min_up parameter. - unsigned sym_up_dl_end; - - tx_timing_parameters(const du_tx_window_timing_parameters& params, - std::chrono::duration symbol_duration) : - sym_cp_dl_start(std::floor(params.T1a_max_cp_dl / symbol_duration)), - sym_cp_dl_end(std::ceil(params.T1a_min_cp_dl / symbol_duration)), - sym_cp_ul_start(std::floor(params.T1a_max_cp_ul / symbol_duration)), - sym_cp_ul_end(std::ceil(params.T1a_min_cp_ul / symbol_duration)), - sym_up_dl_start(std::floor(params.T1a_max_up / symbol_duration)), - sym_up_dl_end(std::ceil(params.T1a_min_up / symbol_duration)) - { - } - }; - /// Logger. srslog::basic_logger& logger; /// Ethernet frame pool. @@ -68,11 +34,11 @@ class message_transmitter_impl : public ota_symbol_boundary_notifier /// Gateway handling message transmission. std::unique_ptr gateway; /// Internal representation of timing parameters. - const tx_timing_parameters timing_params; + const tx_window_timing_parameters timing_params; public: message_transmitter_impl(srslog::basic_logger& logger_, - const symbol_handler_config& cfg, + const tx_window_timing_parameters& timing_params_, std::unique_ptr gw, std::shared_ptr frame_pool); diff --git a/lib/ofh/transmitter/ofh_transmitter_factories.cpp b/lib/ofh/transmitter/ofh_transmitter_factories.cpp index bfad56d33a..ca0b505465 100644 --- a/lib/ofh/transmitter/ofh_transmitter_factories.cpp +++ b/lib/ofh/transmitter/ofh_transmitter_factories.cpp @@ -115,7 +115,7 @@ create_downlink_manager(const transmitter_config& tx_con dl_config.cp = tx_config.cp; dl_config.scs = tx_config.scs; dl_config.dl_processing_time = tx_config.dl_processing_time; - dl_config.tx_timing_params = tx_config.symbol_handler_cfg.tx_timing_params; + dl_config.tx_timing_params = tx_config.tx_timing_params; dl_config.sector = tx_config.sector; downlink_handler_broadcast_impl_dependencies dl_dependencies; @@ -133,7 +133,7 @@ create_downlink_manager(const transmitter_config& tx_con dl_config.cp = tx_config.cp; dl_config.scs = tx_config.scs; dl_config.dl_processing_time = tx_config.dl_processing_time; - dl_config.tx_timing_params = tx_config.symbol_handler_cfg.tx_timing_params; + dl_config.tx_timing_params = tx_config.tx_timing_params; dl_config.sector = tx_config.sector; downlink_handler_impl_dependencies dl_dependencies; diff --git a/lib/ofh/transmitter/ofh_transmitter_impl.cpp b/lib/ofh/transmitter/ofh_transmitter_impl.cpp index 516113c582..35ce6898c7 100644 --- a/lib/ofh/transmitter/ofh_transmitter_impl.cpp +++ b/lib/ofh/transmitter/ofh_transmitter_impl.cpp @@ -18,7 +18,7 @@ transmitter_impl::transmitter_impl(const transmitter_config& config, transmitter dl_manager(std::move(dependencies.dl_manager)), ul_request_handler(std::move(dependencies.ul_request_handler)), msg_transmitter(*dependencies.logger, - config.symbol_handler_cfg, + config.tx_timing_params, std::move(dependencies.eth_gateway), dependencies.frame_pool), ota_dispatcher(*dependencies.executor, dl_manager->get_ota_symbol_boundary_notifier(), msg_transmitter) diff --git a/tests/integrationtests/ofh/ofh_integration_test.cpp b/tests/integrationtests/ofh/ofh_integration_test.cpp index a85be43915..f63a56e9ed 100644 --- a/tests/integrationtests/ofh/ofh_integration_test.cpp +++ b/tests/integrationtests/ofh/ofh_integration_test.cpp @@ -39,9 +39,16 @@ using namespace std::chrono_literals; /// Random generator. static std::mt19937 rgen(0); -/// Static test parameters. -static const du_tx_window_timing_parameters tx_window_timing_params{470us, 258us, 300us, 285us, 350us, 50us}; -static const du_rx_window_timing_parameters rx_window_timing_params{150us, 25us}; +/// Transmission window parameters expressed in symbols, given the 30kHz scs. +unsigned T1a_max_cp_dl = 13; // 470us. +unsigned T1a_min_cp_dl = 8; // 258us. +unsigned T1a_max_cp_ul = 8; // 300us. +unsigned T1a_min_cp_ul = 8; // 285us. +unsigned T1a_max_up = 9; // 350us. +unsigned T1a_min_up = 2; // 50us. +/// Reception window parameters expressed in symbols, given the 30kHz scs. +unsigned Ta4_min = 1; // 150us. +unsigned Ta4_max = 5; // 25us. static const tdd_ul_dl_pattern tdd_pattern_7d2u{10, 7, 0, 2, 0}; static const tdd_ul_dl_pattern tdd_pattern_6d3u{10, 6, 0, 3, 0}; @@ -741,7 +748,9 @@ class test_du_emulator void start() { slot_point slot(0, to_numerology_value(test_params.scs)); - slot_duration_us = std::chrono::microseconds(1000 * SUBFRAME_DURATION_MSEC / slot.nof_slots_per_subframe()); + slot_duration_us = std::chrono::microseconds(1000 * SUBFRAME_DURATION_MSEC / slot.nof_slots_per_subframe()); + symbol_duration_us = std::chrono::microseconds(static_cast( + std::ceil(1e3 / (get_nsymb_per_slot(cyclic_prefix::NORMAL) * get_nof_slots_per_subframe(test_params.scs))))); if (!executor.execute([this]() { run_test(); })) { report_fatal_error("Failed to start DU emulator"); } @@ -782,7 +791,7 @@ class test_du_emulator slot_val = (++slot).to_uint(); } // Leave time fo the uplink slots to be processed. - auto proc_time = processing_delay_slots * slot_duration_us + tx_window_timing_params.T1a_max_cp_ul + 100ms; + auto proc_time = processing_delay_slots * slot_duration_us + (T1a_max_cp_ul * symbol_duration_us) + 100ms; std::this_thread::sleep_for(proc_time); test_finished.store(true, std::memory_order_relaxed); } @@ -796,6 +805,7 @@ class test_du_emulator const unsigned nof_prb; std::chrono::microseconds slot_duration_us; + std::chrono::microseconds symbol_duration_us; std::atomic test_finished{false}; }; @@ -1033,6 +1043,9 @@ static void configure_ofh_sector(ru_ofh_sector_configuration& sector_cfg) // Default IQ data scaling to be applied prior to downlink data compression. const float iq_scaling = 0.9f; + std::chrono::duration symbol_duration( + (1e6 / (get_nsymb_per_slot(cyclic_prefix::NORMAL) * get_nof_slots_per_subframe(test_params.scs)))); + sector_cfg.interface = "lo"; sector_cfg.mac_src_address = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; sector_cfg.mac_dst_address = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; @@ -1043,9 +1056,10 @@ static void configure_ofh_sector(ru_ofh_sector_configuration& sector_cfg) sector_cfg.cp = cyclic_prefix::NORMAL; sector_cfg.is_prach_control_plane_enabled = test_params.is_prach_control_plane_enabled; sector_cfg.ignore_ecpri_payload_size_field = test_params.ignore_ecpri_payload_size_field; - sector_cfg.tx_window_timing_params = tx_window_timing_params; - sector_cfg.rx_window_timing_params = rx_window_timing_params; - sector_cfg.is_downlink_broadcast_enabled = test_params.is_downlink_broadcast_enabled; + sector_cfg.tx_window_timing_params = { + T1a_max_cp_dl, T1a_min_cp_dl, T1a_max_cp_ul, T1a_min_cp_ul, T1a_max_up, T1a_min_up}; + sector_cfg.rx_window_timing_params = {Ta4_min, Ta4_max}; + sector_cfg.is_downlink_broadcast_enabled = test_params.is_downlink_broadcast_enabled; // Configure compression ru_compression_params dl_ul_compression_params{to_compression_type(test_params.data_compr_method), diff --git a/tests/unittests/ofh/ethernet/ethernet_frame_pool_test.cpp b/tests/unittests/ofh/ethernet/ethernet_frame_pool_test.cpp index 356554f089..f7ac7e7802 100644 --- a/tests/unittests/ofh/ethernet/ethernet_frame_pool_test.cpp +++ b/tests/unittests/ofh/ethernet/ethernet_frame_pool_test.cpp @@ -483,9 +483,15 @@ TEST_P(EthFramePoolFixture, clearing_full_pool_should_allow_adding_more_data) } pool.push_frame_buffers(ctx, frame_buffers); } - // Increase slot by pool size, clear stale buffers in the pool and try to get buffers again. + // Increase slot by pool size, clear stale buffers in the pool. auto wrapped_slot = slot + pool_size_slots; pool.clear_downlink_slot(wrapped_slot, logger); + + // Verify the pool is empty in the given slot. + auto rd_buffers = pool.read_frame_buffers(ctx); + ASSERT_TRUE(rd_buffers.empty()) << "No buffers are expected to be read from the pool after clearing it"; + + // Try to get buffers again and make sure they are available. for (unsigned i = 0; i != nof_requested_buffers; ++i) { span frame_buffers = pool.get_frame_buffers(ctx); ASSERT_TRUE(!frame_buffers.empty()) << "Non-empty span of buffers expected"; @@ -511,8 +517,14 @@ TEST_P(EthFramePoolFixture, clearing_full_pool_should_allow_adding_more_data) } pool.push_frame_buffers(ctx, frame_buffers); } - // Clear full slot in the pool and try to get buffers again. + // Clear full slot in the pool. pool.clear_uplink_slot(wrapped_slot, logger); + + // Verify the pool is empty in the given slot. + rd_buffers = pool.read_frame_buffers(ctx); + ASSERT_TRUE(rd_buffers.empty()) << "No buffers are expected to be read from the pool after clearing it"; + + // Try to get buffers again and make sure they are available. for (unsigned i = 0; i != nof_requested_buffers; ++i) { span frame_buffers = pool.get_frame_buffers(ctx); ASSERT_TRUE(!frame_buffers.empty()) << "Non-empty span of buffers expected"; diff --git a/tests/unittests/ofh/receiver/ofh_rx_window_checker_test.cpp b/tests/unittests/ofh/receiver/ofh_rx_window_checker_test.cpp index 81c54e46f2..aa8d519964 100644 --- a/tests/unittests/ofh/receiver/ofh_rx_window_checker_test.cpp +++ b/tests/unittests/ofh/receiver/ofh_rx_window_checker_test.cpp @@ -17,15 +17,14 @@ using namespace std::chrono_literals; TEST(ofh_rx_window_checker, on_time_packet_counts_one_packet) { - du_rx_window_timing_parameters time_params = {std::chrono::microseconds(300), std::chrono::microseconds(50)}; - unsigned nof_symbols_per_slot = 14; - subcarrier_spacing scs = subcarrier_spacing::kHz30; - - rx_window_checker rx_window( - srslog::fetch_basic_logger("TEST"), - time_params, + unsigned nof_symbols_per_slot = 14; + subcarrier_spacing scs = subcarrier_spacing::kHz30; + std::chrono::duration symbol_duration( std::chrono::duration(1e6 / (nof_symbols_per_slot * get_nof_slots_per_subframe(scs)))); + // Create window checker with timing parameters corresponding to Ta4_min=50us, Ta4_max=300us. + rx_window_checker rx_window(srslog::fetch_basic_logger("TEST"), {2, 9}, symbol_duration); + // Create the OTA notification. slot_symbol_point ota_slot({1, 1, 1, 1}, 7, 14); rx_window.on_new_symbol(ota_slot); @@ -39,15 +38,15 @@ TEST(ofh_rx_window_checker, on_time_packet_counts_one_packet) TEST(ofh_rx_window_checker, packet_on_the_window_start_count_as_valid) { - du_rx_window_timing_parameters time_params = {std::chrono::microseconds(300), std::chrono::microseconds(50)}; - unsigned nof_symbols_per_slot = 14; - subcarrier_spacing scs = subcarrier_spacing::kHz30; + unsigned nof_symbols_per_slot = 14; + subcarrier_spacing scs = subcarrier_spacing::kHz30; - rx_window_checker rx_window( - srslog::fetch_basic_logger("TEST"), - time_params, + std::chrono::duration symbol_duration( std::chrono::duration(1e6 / (nof_symbols_per_slot * get_nof_slots_per_subframe(scs)))); + // Create window checker with timing parameters corresponding to Ta4_min=50us, Ta4_max=300us. + rx_window_checker rx_window(srslog::fetch_basic_logger("TEST"), {2, 9}, symbol_duration); + // Create the OTA notification. slot_symbol_point ota_slot({1, 1, 1, 1}, 7, 14); rx_window.on_new_symbol(ota_slot); @@ -61,15 +60,15 @@ TEST(ofh_rx_window_checker, packet_on_the_window_start_count_as_valid) TEST(ofh_rx_window_checker, packet_on_the_window_end_count_as_valid) { - du_rx_window_timing_parameters time_params = {std::chrono::microseconds(510), std::chrono::microseconds(50)}; - unsigned nof_symbols_per_slot = 14; - subcarrier_spacing scs = subcarrier_spacing::kHz30; + unsigned nof_symbols_per_slot = 14; + subcarrier_spacing scs = subcarrier_spacing::kHz30; - rx_window_checker rx_window( - srslog::fetch_basic_logger("TEST"), - time_params, + std::chrono::duration symbol_duration( std::chrono::duration(1e6 / (nof_symbols_per_slot * get_nof_slots_per_subframe(scs)))); + // Create window checker with timing parameters corresponding to Ta4_min=50us, Ta4_max=510us. + rx_window_checker rx_window(srslog::fetch_basic_logger("TEST"), {2, 15}, symbol_duration); + // Create the OTA notification. slot_symbol_point ota_slot({1, 1, 1, 1}, 7, 14); rx_window.on_new_symbol(ota_slot); @@ -83,15 +82,15 @@ TEST(ofh_rx_window_checker, packet_on_the_window_end_count_as_valid) TEST(ofh_rx_window_checker, early_packet_counts_one_packet) { - du_rx_window_timing_parameters time_params = {std::chrono::microseconds(300), std::chrono::microseconds(80)}; - unsigned nof_symbols_per_slot = 14; - subcarrier_spacing scs = subcarrier_spacing::kHz30; + unsigned nof_symbols_per_slot = 14; + subcarrier_spacing scs = subcarrier_spacing::kHz30; - rx_window_checker rx_window( - srslog::fetch_basic_logger("TEST"), - time_params, + std::chrono::duration symbol_duration( std::chrono::duration(1e6 / (nof_symbols_per_slot * get_nof_slots_per_subframe(scs)))); + // Create window checker with timing parameters corresponding to Ta4_min=80us, Ta4_max=300us. + rx_window_checker rx_window(srslog::fetch_basic_logger("TEST"), {3, 9}, symbol_duration); + // Create the OTA notification. slot_symbol_point ota_slot({1, 1, 1, 1}, 7, 14); rx_window.on_new_symbol(ota_slot); @@ -105,15 +104,15 @@ TEST(ofh_rx_window_checker, early_packet_counts_one_packet) TEST(ofh_rx_window_checker, late_packet_counts_one_packet) { - du_rx_window_timing_parameters time_params = {std::chrono::microseconds(300), std::chrono::microseconds(50)}; - unsigned nof_symbols_per_slot = 14; - subcarrier_spacing scs = subcarrier_spacing::kHz30; + unsigned nof_symbols_per_slot = 14; + subcarrier_spacing scs = subcarrier_spacing::kHz30; - rx_window_checker rx_window( - srslog::fetch_basic_logger("TEST"), - time_params, + std::chrono::duration symbol_duration( std::chrono::duration(1e6 / (nof_symbols_per_slot * get_nof_slots_per_subframe(scs)))); + // Create window checker with timing parameters corresponding to Ta4_min=50us, Ta4_max=300us. + rx_window_checker rx_window(srslog::fetch_basic_logger("TEST"), {2, 9}, symbol_duration); + // Create the OTA notification. slot_symbol_point ota_slot({1, 1, 1, 1}, 7, 14); rx_window.on_new_symbol(ota_slot); @@ -127,15 +126,15 @@ TEST(ofh_rx_window_checker, late_packet_counts_one_packet) TEST(ofh_rx_window_checker, window_change_slot_works) { - du_rx_window_timing_parameters time_params = {std::chrono::microseconds(300), std::chrono::microseconds(50)}; - unsigned nof_symbols_per_slot = 14; - subcarrier_spacing scs = subcarrier_spacing::kHz30; + unsigned nof_symbols_per_slot = 14; + subcarrier_spacing scs = subcarrier_spacing::kHz30; - rx_window_checker rx_window( - srslog::fetch_basic_logger("TEST"), - time_params, + std::chrono::duration symbol_duration( std::chrono::duration(1e6 / (nof_symbols_per_slot * get_nof_slots_per_subframe(scs)))); + // Create window checker with timing parameters corresponding to Ta4_min=50us, Ta4_max=300us. + rx_window_checker rx_window(srslog::fetch_basic_logger("TEST"), {2, 9}, symbol_duration); + // Create the OTA notification. slot_symbol_point ota_slot({1, 1, 1, 0}, 1, 14); rx_window.on_new_symbol(ota_slot); @@ -149,15 +148,15 @@ TEST(ofh_rx_window_checker, window_change_slot_works) TEST(ofh_rx_window_checker, window_change_sfn_works) { - du_rx_window_timing_parameters time_params = {std::chrono::microseconds(300), std::chrono::microseconds(50)}; - unsigned nof_symbols_per_slot = 14; - subcarrier_spacing scs = subcarrier_spacing::kHz30; + unsigned nof_symbols_per_slot = 14; + subcarrier_spacing scs = subcarrier_spacing::kHz30; - rx_window_checker rx_window( - srslog::fetch_basic_logger("TEST"), - time_params, + std::chrono::duration symbol_duration( std::chrono::duration(1e6 / (nof_symbols_per_slot * get_nof_slots_per_subframe(scs)))); + // Create window checker with timing parameters corresponding to Ta4_min=50us, Ta4_max=300us. + rx_window_checker rx_window(srslog::fetch_basic_logger("TEST"), {2, 9}, symbol_duration); + // Create the OTA notification. slot_symbol_point ota_slot({1, 1, 0, 0}, 1, 14); rx_window.on_new_symbol(ota_slot); @@ -171,15 +170,15 @@ TEST(ofh_rx_window_checker, window_change_sfn_works) TEST(ofh_rx_window_checker, window_change_sfn_byte_works) { - du_rx_window_timing_parameters time_params = {std::chrono::microseconds(300), std::chrono::microseconds(50)}; - unsigned nof_symbols_per_slot = 14; - subcarrier_spacing scs = subcarrier_spacing::kHz30; + unsigned nof_symbols_per_slot = 14; + subcarrier_spacing scs = subcarrier_spacing::kHz30; - rx_window_checker rx_window( - srslog::fetch_basic_logger("TEST"), - time_params, + std::chrono::duration symbol_duration( std::chrono::duration(1e6 / (nof_symbols_per_slot * get_nof_slots_per_subframe(scs)))); + // Create window checker with timing parameters corresponding to Ta4_min=50us, Ta4_max=300us. + rx_window_checker rx_window(srslog::fetch_basic_logger("TEST"), {2, 9}, symbol_duration); + // Create the OTA notification. slot_symbol_point ota_slot({1, 0, 0, 0}, 1, 14); rx_window.on_new_symbol(ota_slot); @@ -193,15 +192,15 @@ TEST(ofh_rx_window_checker, window_change_sfn_byte_works) TEST(ofh_rx_window_checker, window_change_sfn_byte_and_message_is_in_sfn_0) { - du_rx_window_timing_parameters time_params = {std::chrono::microseconds(300), std::chrono::microseconds(50)}; - unsigned nof_symbols_per_slot = 14; - subcarrier_spacing scs = subcarrier_spacing::kHz30; + unsigned nof_symbols_per_slot = 14; + subcarrier_spacing scs = subcarrier_spacing::kHz30; - rx_window_checker rx_window( - srslog::fetch_basic_logger("TEST"), - time_params, + std::chrono::duration symbol_duration( std::chrono::duration(1e6 / (nof_symbols_per_slot * get_nof_slots_per_subframe(scs)))); + // Create window checker with timing parameters corresponding to Ta4_min=50us, Ta4_max=300us. + rx_window_checker rx_window(srslog::fetch_basic_logger("TEST"), {2, 9}, symbol_duration); + // Create the OTA notification. slot_symbol_point ota_slot({1, 0, 0, 0}, 3, 14); rx_window.on_new_symbol(ota_slot); diff --git a/tests/unittests/ofh/transmitter/ofh_downlink_handler_impl_test.cpp b/tests/unittests/ofh/transmitter/ofh_downlink_handler_impl_test.cpp index de43e297e6..5e305a87cd 100644 --- a/tests/unittests/ofh/transmitter/ofh_downlink_handler_impl_test.cpp +++ b/tests/unittests/ofh/transmitter/ofh_downlink_handler_impl_test.cpp @@ -60,13 +60,11 @@ static downlink_handler_impl_config generate_default_config() config.cp = cyclic_prefix::NORMAL; config.scs = subcarrier_spacing::kHz30; config.dl_processing_time = std::chrono::milliseconds(400); - config.tx_timing_params = {std::chrono::milliseconds(500), - std::chrono::milliseconds(200), - std::chrono::milliseconds(300), - std::chrono::milliseconds(150), - std::chrono::milliseconds(250), - std::chrono::milliseconds(100)}; - + // Transmission timing parameters corresponding to: + // T1a_max_cp_dl=500us, T1a_min_cp_dl=200us, + // T1a_max_cp_ul=300us, T1a_min_cp_ul=150us, + // T1a_max_up=250us, T1a_min_up=100us. + config.tx_timing_params = {13, 6, 8, 5, 6, 3}; return config; } From 2a69309d98d6fc39a8ee5a8f1130a56b058903d1 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Wed, 6 Mar 2024 11:34:15 +0100 Subject: [PATCH 100/140] cu_cp,ngap: fix release command handling --- lib/ngap/ngap_impl.cpp | 36 ++++++++++++------- ...handover_resource_allocation_procedure.cpp | 2 +- lib/ngap/ue_context/ngap_ue_context.h | 2 +- ...p_ue_context_management_procedure_test.cpp | 20 +++++++++++ 4 files changed, 46 insertions(+), 14 deletions(-) diff --git a/lib/ngap/ngap_impl.cpp b/lib/ngap/ngap_impl.cpp index d3c80e554d..6ed6668ee1 100644 --- a/lib/ngap/ngap_impl.cpp +++ b/lib/ngap/ngap_impl.cpp @@ -277,7 +277,7 @@ void ngap_impl::handle_dl_nas_transport_message(const asn1::ngap::dl_nas_transpo // Add AMF UE ID to ue ngap context if it is not set (this is the first DL NAS Transport message) if (ue_ctxt.ue_ids.amf_ue_id == amf_ue_id_t::invalid) { // Set AMF UE ID in the UE context and also in the lookup - ue_ctxt_list.add_amf_ue_id(ue_ctxt.ue_ids.ran_ue_id, uint_to_amf_ue_id(msg->amf_ue_ngap_id)); + ue_ctxt_list.update_amf_ue_id(ue_ctxt.ue_ids.ran_ue_id, uint_to_amf_ue_id(msg->amf_ue_ngap_id)); } ue_ctxt.logger.log_info("Received DlNasTransportMessage"); @@ -321,7 +321,7 @@ void ngap_impl::handle_initial_context_setup_request(const asn1::ngap::init_cont ue_ctxt.logger.log_info("Received InitialContextSetupRequest"); // Update AMF ID and use the one from this Context Setup as per TS 38.413 v16.2 page 38 - ue_ctxt_list.add_amf_ue_id(ue_ctxt.ue_ids.ran_ue_id, uint_to_amf_ue_id(request->amf_ue_ngap_id)); + ue_ctxt_list.update_amf_ue_id(ue_ctxt.ue_ids.ran_ue_id, uint_to_amf_ue_id(request->amf_ue_ngap_id)); // Convert to common type ngap_init_context_setup_request init_ctxt_setup_req; @@ -545,19 +545,31 @@ void ngap_impl::handle_ue_context_release_command(const asn1::ngap::ue_context_r ran_ue_id_t ran_ue_id = ran_ue_id_t::invalid; if (cmd->ue_ngap_ids.type() == asn1::ngap::ue_ngap_ids_c::types_opts::amf_ue_ngap_id) { amf_ue_id = uint_to_amf_ue_id(cmd->ue_ngap_ids.amf_ue_ngap_id()); + + if (!ue_ctxt_list.contains(amf_ue_id)) { + // TS 38.413 section 8.3.3 doesn't specify abnormal conditions, so we just drop the message and send an error + // indication + logger.warning("{}amf_ue_id={}: Dropping UeContextReleaseCommand. UE does not exist", + ran_ue_id == ran_ue_id_t::invalid ? "" : fmt::format("ran_ue_id={} ", ran_ue_id), + amf_ue_id); + send_error_indication(ngap_notifier, logger, {}, amf_ue_id, ngap_cause_radio_network_t::unknown_local_ue_ngap_id); + return; + } } else if (cmd->ue_ngap_ids.type() == asn1::ngap::ue_ngap_ids_c::types_opts::ue_ngap_id_pair) { amf_ue_id = uint_to_amf_ue_id(cmd->ue_ngap_ids.ue_ngap_id_pair().amf_ue_ngap_id); ran_ue_id = uint_to_ran_ue_id(cmd->ue_ngap_ids.ue_ngap_id_pair().ran_ue_ngap_id); - } - if (!ue_ctxt_list.contains(amf_ue_id)) { - // TS 38.413 section 8.3.3 doesn't specify abnormal conditions, so we just drop the message and send an error - // indication - logger.warning("{}amf_ue_id={}: Dropping UeContextReleaseCommand. UE does not exist", - ran_ue_id == ran_ue_id_t::invalid ? "" : fmt::format("ran_ue_id={} ", ran_ue_id), - amf_ue_id); - send_error_indication(ngap_notifier, logger, {}, amf_ue_id, ngap_cause_radio_network_t::unknown_local_ue_ngap_id); - return; + if (!ue_ctxt_list.contains(ran_ue_id)) { + // TS 38.413 section 8.3.3 doesn't specify abnormal conditions, so we just drop the message and send an error + // indication + logger.warning( + "ran_ue_id={} amf_ue_id={}: Dropping UeContextReleaseCommand. UE does not exist", ran_ue_id, amf_ue_id); + send_error_indication(ngap_notifier, logger, {}, amf_ue_id, ngap_cause_radio_network_t::unknown_local_ue_ngap_id); + return; + } + + // Update AMF UE ID + ue_ctxt_list.update_amf_ue_id(ran_ue_id, amf_ue_id); } ngap_ue_context& ue_ctxt = ue_ctxt_list[amf_ue_id]; @@ -576,7 +588,7 @@ void ngap_impl::handle_ue_context_release_command(const asn1::ngap::ue_context_r // Add AMF UE ID to UE, if its not set if (ue_ctxt.ue_ids.amf_ue_id == amf_ue_id_t::invalid) { - ue_ctxt_list.add_amf_ue_id(ran_ue_id, amf_ue_id); + ue_ctxt_list.update_amf_ue_id(ran_ue_id, amf_ue_id); } ngap_ue* ue = ue_manager.find_ngap_ue(ue_ctxt.ue_ids.ue_index); diff --git a/lib/ngap/procedures/ngap_handover_resource_allocation_procedure.cpp b/lib/ngap/procedures/ngap_handover_resource_allocation_procedure.cpp index 5f92e80856..8ada5b66fc 100644 --- a/lib/ngap/procedures/ngap_handover_resource_allocation_procedure.cpp +++ b/lib/ngap/procedures/ngap_handover_resource_allocation_procedure.cpp @@ -53,7 +53,7 @@ void ngap_handover_resource_allocation_procedure::operator()(coro_contexthandle_message(ue_context_release_cmd); + + ASSERT_TRUE(was_ue_context_release_complete_sent()); + ASSERT_TRUE(was_ue_removed()); +} + /// Test successful UE context release TEST_F(ngap_ue_context_management_procedure_test, when_ue_context_release_command_with_amf_ue_ngap_id_received_then_ue_is_released_and_release_complete_is_sent) From e12894140c04a1172c4820455cd8d3f8b17f6053 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Wed, 6 Mar 2024 11:34:29 +0100 Subject: [PATCH 101/140] cu_cp: improve logging --- lib/cu_cp/up_resource_manager/up_resource_manager_helpers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cu_cp/up_resource_manager/up_resource_manager_helpers.cpp b/lib/cu_cp/up_resource_manager/up_resource_manager_helpers.cpp index 85bc6a1404..9031d4b9ef 100644 --- a/lib/cu_cp/up_resource_manager/up_resource_manager_helpers.cpp +++ b/lib/cu_cp/up_resource_manager/up_resource_manager_helpers.cpp @@ -104,7 +104,7 @@ bool srsran::srs_cu_cp::is_valid( // Reject request if PDU session with same ID already exists. for (const auto& pdu_session : setup_items) { if (context.pdu_sessions.find(pdu_session.pdu_session_id) != context.pdu_sessions.end()) { - logger.debug("PDU session ID {} already exists", pdu_session.pdu_session_id); + logger.info("PDU session ID {} already exists", pdu_session.pdu_session_id); return false; } From 34205c0c35f9480416096b2409add8a7c1f5bc78 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Wed, 6 Mar 2024 13:55:57 +0100 Subject: [PATCH 102/140] cu_cp,ngap: improve amf ue id update --- lib/ngap/ngap_impl.cpp | 9 +++++++-- lib/ngap/ue_context/ngap_ue_context.h | 20 +++++++++++++++++--- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/lib/ngap/ngap_impl.cpp b/lib/ngap/ngap_impl.cpp index 6ed6668ee1..637789eb4b 100644 --- a/lib/ngap/ngap_impl.cpp +++ b/lib/ngap/ngap_impl.cpp @@ -321,7 +321,9 @@ void ngap_impl::handle_initial_context_setup_request(const asn1::ngap::init_cont ue_ctxt.logger.log_info("Received InitialContextSetupRequest"); // Update AMF ID and use the one from this Context Setup as per TS 38.413 v16.2 page 38 - ue_ctxt_list.update_amf_ue_id(ue_ctxt.ue_ids.ran_ue_id, uint_to_amf_ue_id(request->amf_ue_ngap_id)); + if (ue_ctxt.ue_ids.amf_ue_id != uint_to_amf_ue_id(request->amf_ue_ngap_id)) { + ue_ctxt_list.update_amf_ue_id(ue_ctxt.ue_ids.ran_ue_id, uint_to_amf_ue_id(request->amf_ue_ngap_id)); + } // Convert to common type ngap_init_context_setup_request init_ctxt_setup_req; @@ -569,7 +571,10 @@ void ngap_impl::handle_ue_context_release_command(const asn1::ngap::ue_context_r } // Update AMF UE ID - ue_ctxt_list.update_amf_ue_id(ran_ue_id, amf_ue_id); + if (ue_ctxt_list[ran_ue_id].ue_ids.amf_ue_id == amf_ue_id_t::invalid or + ue_ctxt_list[ran_ue_id].ue_ids.amf_ue_id != amf_ue_id) { + ue_ctxt_list.update_amf_ue_id(ran_ue_id, amf_ue_id); + } } ngap_ue_context& ue_ctxt = ue_ctxt_list[amf_ue_id]; diff --git a/lib/ngap/ue_context/ngap_ue_context.h b/lib/ngap/ue_context/ngap_ue_context.h index 7c4d08e177..b41c51b332 100644 --- a/lib/ngap/ue_context/ngap_ue_context.h +++ b/lib/ngap/ue_context/ngap_ue_context.h @@ -125,9 +125,23 @@ class ngap_ue_context_list srsran_assert(ues.find(ran_ue_id) != ues.end(), "ran_ue_id={}: NGAP UE context not found", ran_ue_id); auto& ue = ues.at(ran_ue_id); - ue.logger.log_debug("Adding amf_ue_id={}", amf_ue_id); - ue.ue_ids.amf_ue_id = amf_ue_id; - amf_ue_id_to_ran_ue_id.emplace(amf_ue_id, ran_ue_id); + + if (ue.ue_ids.amf_ue_id == amf_ue_id) { + // If the AMF-UE-ID is already set, we don't want to change it. + return; + } else if (ue.ue_ids.amf_ue_id == amf_ue_id_t::invalid) { + // If it was not set before, we add it + ue.logger.log_debug("Adding amf_ue_id={}", amf_ue_id); + ue.ue_ids.amf_ue_id = amf_ue_id; + amf_ue_id_to_ran_ue_id.emplace(amf_ue_id, ran_ue_id); + } else if (ue.ue_ids.amf_ue_id != amf_ue_id) { + // If it was set before, we update it + amf_ue_id_t old_amf_ue_id = ue.ue_ids.amf_ue_id; + ue.logger.log_info("Updating AMF-UE-ID. New amf_ue_id={}", amf_ue_id); + ue.ue_ids.amf_ue_id = amf_ue_id; + amf_ue_id_to_ran_ue_id.emplace(amf_ue_id, ran_ue_id); + amf_ue_id_to_ran_ue_id.erase(old_amf_ue_id); + } ue.logger.set_prefix({ue.ue_ids.ue_index, ran_ue_id, amf_ue_id}); } From 033838983f2b94ef8c120870d568de7c6e3e4f2d Mon Sep 17 00:00:00 2001 From: asaezper Date: Tue, 5 Mar 2024 13:39:48 +0100 Subject: [PATCH 103/140] ci,e2e: adjust inactivity timer --- tests/e2e/tests/iperf.py | 2 +- tests/e2e/tests/ping.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/e2e/tests/iperf.py b/tests/e2e/tests/iperf.py index c621b033a8..1941e4fa4d 100644 --- a/tests/e2e/tests/iperf.py +++ b/tests/e2e/tests/iperf.py @@ -517,7 +517,7 @@ def test_zmq( time_alignment_calibration=0, always_download_artifacts=always_download_artifacts, bitrate_threshold=0, - gnb_post_cmd="log --hex_max_size=32", + gnb_post_cmd="log --hex_max_size=32 cu_cp --inactivity_timer=600", ) diff --git a/tests/e2e/tests/ping.py b/tests/e2e/tests/ping.py index 0d4dcefd96..fafc9c2f30 100644 --- a/tests/e2e/tests/ping.py +++ b/tests/e2e/tests/ping.py @@ -168,6 +168,7 @@ def test_zmq( sample_rate=None, # default from testbed global_timing_advance=0, time_alignment_calibration=0, + post_command="cu_cp --inactivity_timer=600", ) From c093028aee0ddb309b6dc7b35a255ff7a9b0ae20 Mon Sep 17 00:00:00 2001 From: asaezper Date: Tue, 5 Mar 2024 17:05:52 +0100 Subject: [PATCH 104/140] ci,e2e: add zmq test using generated deb file --- .gitlab/ci/build.yml | 21 ++++++- .gitlab/ci/e2e.yml | 13 +++++ .gitlab/ci/e2e/.env | 1 + .gitlab/ci/e2e/retina_request_zmq_deb.yml | 68 +++++++++++++++++++++++ 4 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 .gitlab/ci/e2e/retina_request_zmq_deb.yml diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 42d23401e6..a99c25ce7d 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -8,7 +8,7 @@ include: - project: softwareradiosystems/ci/srsran_project_packaging - ref: "3" + ref: "4" file: .gitlab/ci-shared/package.yml - local: .gitlab/ci/src_cache.yml @@ -17,7 +17,9 @@ variables: AMD64_AVX2_TAG: amd64-avx2 AMD64_AVX512_TAG: amd64-avx2-avx512 ARM64_TAG: arm64 + AMD64_LIB_BUILDER_TAG: on-prem-amd64 + AMD64_VIAVI_BUILDER_TAG: on-prem-amd64-avx2-avx512 INFRASTRUCTURE_TAG: description: Computer architecture and supported instruction sets @@ -739,7 +741,7 @@ package: - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ when: delayed start_in: 30 minutes - variables: + variables: &package_variables PROJECT_NAME: srsran-project RELEASE_VERSION: "99.9" KUBERNETES_CPU_REQUEST: 7 @@ -1718,6 +1720,19 @@ basic relwithdeb: <<: *build_artifacts expire_in: 3 day +basic package: + extends: .deb-package + stage: build and unit tests + rules: + - if: $CI_DESCRIPTION =~ /Nightly E2E Tests/ + retry: 2 + interruptible: false + variables: + <<: *package_variables + OS_VERSION: "24.04" + tags: ["${AMD64_LIB_BUILDER_TAG}"] + needs: [] + basic tsan: extends: .smoke tsan rules: @@ -1783,7 +1798,7 @@ basic avx512 dpdk: KUBERNETES_CPU_LIMIT: 14 KUBERNETES_MEMORY_REQUEST: 20Gi KUBERNETES_MEMORY_LIMIT: 20Gi - tags: ["on-prem-amd64-avx2-avx512"] + tags: ["${AMD64_VIAVI_BUILDER_TAG}"] artifacts: <<: *build_artifacts expire_in: 3 day diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 9a3b1dc23d..b6c313520e 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -16,6 +16,7 @@ variables: description: Retina Testbed Description options: - "zmq" + - "zmq_deb" - "zmq_single_ue" - "zmq_4x4_mimo" - "zmq_srsue" @@ -255,6 +256,18 @@ amari 1UE 4x4 mimo: - *txrx-lib - *retina-needs +amari 4UE deb: + extends: .zmq + variables: + TESTBED: "zmq_deb" + MARKERS: "smoke" + E2E_LOG_LEVEL: "info" + needs: + - job: "basic package" + artifacts: true + - *txrx-lib + - *retina-needs + amari 32UE: extends: .zmq variables: diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index 6db6c0267c..b6ac009879 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -1,6 +1,7 @@ SRSGNB_REGISTRY_URI=registry.gitlab.com/softwareradiosystems/srsgnb RETINA_REGISTRY_PREFIX=registry.gitlab.com/softwareradiosystems/ci/retina RETINA_VERSION=0.44.1 +UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2024-02-20 SRSUE_VERSION=23.11 OPEN5GS_VERSION=2.6.6 diff --git a/.gitlab/ci/e2e/retina_request_zmq_deb.yml b/.gitlab/ci/e2e/retina_request_zmq_deb.yml new file mode 100644 index 0000000000..f7bc886105 --- /dev/null +++ b/.gitlab/ci/e2e/retina_request_zmq_deb.yml @@ -0,0 +1,68 @@ +# +# Copyright 2013-2024 Software Radio Systems Limited +# +# By using this file, you agree to the terms and conditions set +# forth in the LICENSE file which can be found at the top level of +# the distribution. +# + +- name: amarisoft-ue + type: ue + image: ${RETINA_REGISTRY_PREFIX}/amarisoftue:${AMARISOFT_VERSION}_${RETINA_VERSION} + labels: + - ${ZMQ_HOSTLABEL_1} + nof_ports: 4 + requirements: + arch: amd64 + cpu: + requests: 1 + memory: + requests: "8G" + ephemeral-storage: + requests: "6G" + limits: "6G" + resources: + - type: zmq + - type: license + model: amarisoft-5g + shared_files: + - local_path: ../../build_trx_srsran/libtrx_srsran.so + remote_path: /opt/lteue/trx_srsran.so + is_executable: true + +- name: srs-gnb + type: gnb + image: ${RETINA_REGISTRY_PREFIX}/agent-ubuntu-${UBUNTU_VERSION}:${RETINA_VERSION} + labels: + - ${ZMQ_HOSTLABEL_1} + requirements: + arch: amd64 + cpu: + requests: 1 + memory: + requests: "8G" + limits: "8G" + ephemeral-storage: + requests: "6G" + limits: "6G" + resources: + - type: zmq + shared_files: + - local_path: ../../srsran-project_99.9-0ubuntu1ppa1~24.04_amd64.deb + remote_path: /tmp/retina-libs/srsran-project.deb + is_executable: false + +- name: open5gs + type: 5gc + requirements: + arch: amd64 + cpu: + requests: 1 + memory: + requests: "4G" + ephemeral-storage: + requests: "6G" + limits: "6G" + image: ${RETINA_REGISTRY_PREFIX}/open5gs:${OPEN5GS_VERSION}_${RETINA_VERSION} + labels: + - ${ZMQ_HOSTLABEL_1} From 9564f975c443d80e26cb98f8ab3d53ca37892466 Mon Sep 17 00:00:00 2001 From: Joaquim Broquetas Date: Wed, 6 Mar 2024 14:43:16 +0100 Subject: [PATCH 105/140] gnb: config parameter for low PHY DL buffer size policy --- apps/gnb/gnb_appconfig.h | 11 ++++++++++ apps/gnb/gnb_appconfig_cli11_schema.cpp | 14 ++++++++++++ apps/gnb/gnb_appconfig_translators.cpp | 22 +++++++++++++++---- apps/gnb/gnb_appconfig_validators.cpp | 9 ++++++++ .../phy/lower/lower_phy_configuration.h | 18 +++++++++++++++ 5 files changed, 70 insertions(+), 4 deletions(-) diff --git a/apps/gnb/gnb_appconfig.h b/apps/gnb/gnb_appconfig.h index ad2d8239a6..73918ace02 100644 --- a/apps/gnb/gnb_appconfig.h +++ b/apps/gnb/gnb_appconfig.h @@ -922,6 +922,17 @@ struct ru_sdr_expert_appconfig { /// \note Powering up the transmitter ahead of time requires starting the transmission earlier, and reduces the time /// window for the radio to transmit the provided samples. float power_ramping_time_us = 0.0F; + /// \brief Lower PHY downlink baseband buffer size policy. + /// + /// Selects the size policy of the baseband buffers that pass DL samples from the lower PHY to the radio. + /// Available options: + /// - auto: the size policy is automatically selected based on the SDR front-end. + /// - single-packet: the buffer size matches the optimal buffer size indicated by the SDR front-end. + /// - half-slot: the buffer size matches the number of samples per half-slot. + /// - slot: the buffer size matches the number of samples per slot. + /// - optimal-slot: the buffer size is equal to the greatest multiple of the optimal buffer size indicated by the + /// SDR front-end that results in a buffer size smaller than the number of samples per slot. + std::string dl_buffer_size_policy = "auto"; }; /// gNB app SDR Radio Unit configuration. diff --git a/apps/gnb/gnb_appconfig_cli11_schema.cpp b/apps/gnb/gnb_appconfig_cli11_schema.cpp index 13d18a2e51..e04032a7c0 100644 --- a/apps/gnb/gnb_appconfig_cli11_schema.cpp +++ b/apps/gnb/gnb_appconfig_cli11_schema.cpp @@ -1665,6 +1665,14 @@ static void configure_cli11_test_mode_args(CLI::App& app, test_mode_appconfig& t static void configure_cli11_ru_sdr_expert_args(CLI::App& app, ru_sdr_expert_appconfig& config) { + auto buffer_size_policy_check = [](const std::string& value) -> std::string { + if (value == "auto" || value == "single-packet" || value == "half-slot" || value == "slot" || + value == "optimal-slot") { + return {}; + } + return "Invalid DL buffer size policy. Accepted values [auto,single-packet,half-slot,slot,optimal-slot]"; + }; + app.add_option("--low_phy_dl_throttling", config.lphy_dl_throttling, "Throttles the lower PHY DL baseband generation. The range is (0, 1). Set it to zero to disable it.") @@ -1678,6 +1686,12 @@ static void configure_cli11_ru_sdr_expert_args(CLI::App& app, ru_sdr_expert_appc "Specifies the power ramping time in microseconds, it proactively initiates the transmission and " "mitigates transient effects.") ->capture_default_str(); + app.add_option( + "--dl_buffer_size_policy", + config.dl_buffer_size_policy, + "Selects the size policy of the baseband buffers that pass DL samples from the lower PHY to the radio.") + ->capture_default_str() + ->check(buffer_size_policy_check); } static void configure_cli11_ru_sdr_args(CLI::App& app, ru_sdr_appconfig& config) diff --git a/apps/gnb/gnb_appconfig_translators.cpp b/apps/gnb/gnb_appconfig_translators.cpp index 605709cc43..d1085a7a2c 100644 --- a/apps/gnb/gnb_appconfig_translators.cpp +++ b/apps/gnb/gnb_appconfig_translators.cpp @@ -1221,21 +1221,35 @@ static void generate_low_phy_config(lower_phy_configuration& out_cfg, out_cfg.time_alignment_calibration = 0; } - // Select buffer size policy. + // Select RX buffer size policy. if (ru_cfg.device_driver == "zmq") { - out_cfg.baseband_tx_buffer_size_policy = lower_phy_baseband_buffer_size_policy::half_slot; out_cfg.baseband_rx_buffer_size_policy = lower_phy_baseband_buffer_size_policy::half_slot; } else if (low_phy_threads_cfg.execution_profile == lower_phy_thread_profile::single) { // For single executor, the same executor processes uplink and downlink. In this case, the processing is blocked // by the signal reception. The buffers must be smaller than a slot duration considering the downlink baseband // samples must arrive to the baseband device before the transmission time passes. - out_cfg.baseband_tx_buffer_size_policy = lower_phy_baseband_buffer_size_policy::single_packet; out_cfg.baseband_rx_buffer_size_policy = lower_phy_baseband_buffer_size_policy::single_packet; } else { - out_cfg.baseband_tx_buffer_size_policy = lower_phy_baseband_buffer_size_policy::slot; out_cfg.baseband_rx_buffer_size_policy = lower_phy_baseband_buffer_size_policy::single_packet; } + // Select TX buffer size policy. + if (ru_cfg.expert_cfg.dl_buffer_size_policy == "auto") { + if (ru_cfg.device_driver == "zmq") { + out_cfg.baseband_tx_buffer_size_policy = lower_phy_baseband_buffer_size_policy::half_slot; + } else if (low_phy_threads_cfg.execution_profile == lower_phy_thread_profile::single) { + // For single executor, the same executor processes uplink and downlink. In this case, the processing is blocked + // by the signal reception. The buffers must be smaller than a slot duration considering the downlink baseband + // samples must arrive to the baseband device before the transmission time passes. + out_cfg.baseband_tx_buffer_size_policy = lower_phy_baseband_buffer_size_policy::single_packet; + } else { + out_cfg.baseband_tx_buffer_size_policy = lower_phy_baseband_buffer_size_policy::slot; + } + } else { + // Manual selection of the TX buffer size policy. + out_cfg.baseband_tx_buffer_size_policy = to_buffer_size_policy(ru_cfg.expert_cfg.dl_buffer_size_policy); + } + // Get lower PHY system time throttling. out_cfg.system_time_throttling = ru_cfg.expert_cfg.lphy_dl_throttling; diff --git a/apps/gnb/gnb_appconfig_validators.cpp b/apps/gnb/gnb_appconfig_validators.cpp index 6652bcc87f..959e90ddd6 100644 --- a/apps/gnb/gnb_appconfig_validators.cpp +++ b/apps/gnb/gnb_appconfig_validators.cpp @@ -1227,6 +1227,15 @@ static bool validate_expert_execution_appconfig(const gnb_appconfig& config) return false; } + if (variant_holds_alternative(config.ru_cfg)) { + auto& sdr_cfg = variant_get(config.ru_cfg); + if ((config.expert_execution_cfg.threads.lower_threads.execution_profile == lower_phy_thread_profile::single) && + (sdr_cfg.expert_cfg.dl_buffer_size_policy != "auto")) { + fmt::print("DL buffer size policy must be set to auto when single thread lower PHY profile is used.\n"); + return false; + } + } + // Configure more cells for expert execution than the number of cells is an error. if (config.expert_execution_cfg.cell_affinities.size() > config.cells_cfg.size()) { fmt::print("Using more cells for expert execution '{}' than the number of defined cells '{}'\n", diff --git a/include/srsran/phy/lower/lower_phy_configuration.h b/include/srsran/phy/lower/lower_phy_configuration.h index 810ee07dae..efe59094fa 100644 --- a/include/srsran/phy/lower/lower_phy_configuration.h +++ b/include/srsran/phy/lower/lower_phy_configuration.h @@ -121,6 +121,24 @@ struct lower_phy_configuration { task_executor* prach_async_executor; }; +/// Converts a string into a baseband buffer size policy. +inline lower_phy_baseband_buffer_size_policy to_buffer_size_policy(const std::string& str) +{ + if (str == "single-packet") { + return lower_phy_baseband_buffer_size_policy::single_packet; + } + if (str == "half-slot") { + return lower_phy_baseband_buffer_size_policy::half_slot; + } + if (str == "slot") { + return lower_phy_baseband_buffer_size_policy::slot; + } + if (str == "optimal-slot") { + return lower_phy_baseband_buffer_size_policy::optimal_slot; + } + report_error("Invalid lower PHY baseband buffer size policy '{}'.", str); +} + /// Returns true if the given lower PHY configuration is valid, otherwise false. inline bool is_valid_lower_phy_config(const lower_phy_configuration& config) { From 663240cfd978292199cd7b46a4eae6e2c53ce909 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 13 Feb 2024 15:00:44 +0100 Subject: [PATCH 106/140] phy: improve PUSCH TPMI selection phy: more TPMI selection development phy: fix PUSCH TPMI select --- include/srsran/ran/pusch/pusch_tpmi_select.h | 3 + lib/ran/pusch/pusch_tpmi_select.cpp | 102 ++++++++++++++---- .../ran/pusch/pusch_tpmi_select_test.cpp | 7 +- .../ran/pusch/pusch_tpmi_select_test_data.h | 2 +- 4 files changed, 94 insertions(+), 20 deletions(-) diff --git a/include/srsran/ran/pusch/pusch_tpmi_select.h b/include/srsran/ran/pusch/pusch_tpmi_select.h index a87fd89572..8430757024 100644 --- a/include/srsran/ran/pusch/pusch_tpmi_select.h +++ b/include/srsran/ran/pusch/pusch_tpmi_select.h @@ -50,6 +50,9 @@ class pusch_tpmi_select_info return info[nof_layers - 1]; } + /// Constructs a PUSCH TPMI information from a span. + pusch_tpmi_select_info(const span& info_) : info(info_.begin(), info_.end()) {} + /// Constructs a PUSCH TPMI information from an initializer list. pusch_tpmi_select_info(const std::initializer_list& info_) : info(info_.begin(), info_.end()) {} diff --git a/lib/ran/pusch/pusch_tpmi_select.cpp b/lib/ran/pusch/pusch_tpmi_select.cpp index 4b742aea95..3ab078acec 100644 --- a/lib/ran/pusch/pusch_tpmi_select.cpp +++ b/lib/ran/pusch/pusch_tpmi_select.cpp @@ -10,18 +10,25 @@ #include "srsran/ran/pusch/pusch_tpmi_select.h" #include "srsran/adt/complex.h" +#include "srsran/adt/span.h" +#include "srsran/adt/static_vector.h" #include "srsran/ran/precoding/precoding_weight_matrix.h" +#include "srsran/ran/pusch/pusch_constants.h" #include "srsran/ran/srs/srs_channel_matrix.h" #include "srsran/support/math_utils.h" +#include #include #include +#include using namespace srsran; static constexpr cf_t sqrt1_2(M_SQRT1_2, 0); - static constexpr cf_t sqrt1_2j(0, M_SQRT1_2); +static constexpr cf_t dot5(0.5, 0); +static constexpr cf_t dot5j(0, 0.5); +// TS38.211 Table 6.3.1.5-1 static const std::array codebook_1layer_2port = { {precoding_weight_matrix({sqrt1_2, 0}, 1, 2), precoding_weight_matrix({0, sqrt1_2}, 1, 2), @@ -30,44 +37,103 @@ static const std::array codebook_1layer_2port = { precoding_weight_matrix({sqrt1_2, sqrt1_2j}, 1, 2), precoding_weight_matrix({sqrt1_2, -sqrt1_2j}, 1, 2)}}; -static pusch_tpmi_select_info get_tpmi_select_info_1x2(const srs_channel_matrix& channel, float noise_variance) +// TS38.211 Table 6.3.1.5-3 +static const std::array codebook_1layer_4port = {{ + // TPMI Index 0-7 + precoding_weight_matrix({dot5, 0, 0, 0}, 1, 4), + precoding_weight_matrix({0, dot5, 0, 0}, 1, 4), + precoding_weight_matrix({0, 0, dot5, 0}, 1, 4), + precoding_weight_matrix({0, 0, 0, dot5}, 1, 4), + precoding_weight_matrix({dot5, 0, dot5, 0}, 1, 4), + precoding_weight_matrix({dot5, 0, -dot5, 0}, 1, 4), + precoding_weight_matrix({dot5, 0, dot5j, 0}, 1, 4), + precoding_weight_matrix({dot5, 0, -dot5j, 0}, 1, 4), + // TPMI Index 8-15 + precoding_weight_matrix({0, dot5, 0, dot5}, 1, 4), + precoding_weight_matrix({0, dot5, 0, -dot5}, 1, 4), + precoding_weight_matrix({0, dot5, 0, dot5j}, 1, 4), + precoding_weight_matrix({0, dot5, 0, -dot5j}, 1, 4), + precoding_weight_matrix({dot5, dot5, dot5, dot5}, 1, 4), + precoding_weight_matrix({dot5, dot5, dot5j, dot5j}, 1, 4), + precoding_weight_matrix({dot5, dot5, -dot5, -dot5}, 1, 4), + precoding_weight_matrix({dot5, dot5, -dot5j, -dot5j}, 1, 4), + // TPMI Index 16-23 + precoding_weight_matrix({dot5, dot5j, dot5, dot5j}, 1, 4), + precoding_weight_matrix({dot5, dot5j, dot5j, -dot5}, 1, 4), + precoding_weight_matrix({dot5, dot5j, -dot5, -dot5j}, 1, 4), + precoding_weight_matrix({dot5, dot5j, -dot5j, dot5}, 1, 4), + precoding_weight_matrix({dot5, -dot5, dot5, -dot5}, 1, 4), + precoding_weight_matrix({dot5, -dot5, dot5j, -dot5j}, 1, 4), + precoding_weight_matrix({dot5, -dot5, -dot5, dot5}, 1, 4), + precoding_weight_matrix({dot5, -dot5, -dot5j, dot5j}, 1, 4), + // TPMI Index 24-27 + precoding_weight_matrix({dot5, -dot5j, dot5, -dot5j}, 1, 4), + precoding_weight_matrix({dot5, -dot5j, dot5j, dot5}, 1, 4), + precoding_weight_matrix({dot5, -dot5j, -dot5, dot5j}, 1, 4), + precoding_weight_matrix({dot5, -dot5j, -dot5j, -dot5}, 1, 4), +}}; + +static pusch_tpmi_select_info::tpmi_info get_tpmi_select_info_1layer(const srs_channel_matrix& channel, + float noise_variance) { + unsigned nof_rx_ports = channel.get_nof_rx_ports(); + unsigned nof_tx_ports = channel.get_nof_tx_ports(); + + // Select codebook in function of the number of transmit ports. + span codebook = codebook_1layer_2port; + if (nof_tx_ports == 4) { + codebook = codebook_1layer_4port; + } + float best_sinr = -std::numeric_limits::infinity(); unsigned best_tpmi = 0; // Iterate possible TPMIs. - for (unsigned tpmi = 0, tpmi_end = codebook_1layer_2port.size(); tpmi != tpmi_end; ++tpmi) { + for (unsigned tpmi = 0, tpmi_end = codebook.size(); tpmi != tpmi_end; ++tpmi) { // Select precoding matrix. - const precoding_weight_matrix& w = codebook_1layer_2port[tpmi]; - cf_t w_p0 = w.get_coefficient(0, 0); - cf_t w_p1 = w.get_coefficient(0, 1); + const precoding_weight_matrix& weights = codebook[tpmi]; - cf_t h_00 = channel.get_coefficient(0, 0); - cf_t h_01 = channel.get_coefficient(0, 1); + float signal_power = 0; - cf_t wh = w_p0 * h_00 + w_p1 * h_01; - float whhw = abs_sq(wh); + // Combine channel coefficients with precoding weights. + for (unsigned i_rx_port = 0; i_rx_port != nof_rx_ports; ++i_rx_port) { + cf_t sum = 0; + for (unsigned i_tx_port = 0; i_tx_port != nof_tx_ports; ++i_tx_port) { + // Select precoding weight. + cf_t w = weights.get_coefficient(0, i_tx_port); + // Select channel coefficient. + cf_t h = channel.get_coefficient(i_rx_port, i_tx_port); - float sinr = whhw / noise_variance; + // Sum absolute square. + sum += h * w; + } + + signal_power += abs_sq(sum); + } + + float sinr = signal_power / noise_variance; if (sinr > best_sinr) { best_sinr = sinr; best_tpmi = tpmi; } } - return {{best_tpmi, convert_power_to_dB(best_sinr)}}; + return {best_tpmi, convert_power_to_dB(best_sinr)}; } pusch_tpmi_select_info srsran::get_tpmi_select_info(const srs_channel_matrix& channel, float noise_variance) { - unsigned nof_tx_ports = channel.get_nof_tx_ports(); - unsigned nof_rx_ports = channel.get_nof_rx_ports(); + unsigned nof_tx_ports = channel.get_nof_tx_ports(); + unsigned nof_rx_ports = channel.get_nof_rx_ports(); + unsigned max_nof_layers = std::min(nof_tx_ports, nof_rx_ports); + + static_vector info; - // Two transmit, one receive ports. - if ((nof_tx_ports == 2) && (nof_rx_ports == 1)) { - return get_tpmi_select_info_1x2(channel, noise_variance); + // Calculate TPMI select information for 1 layer. + if (max_nof_layers >= 1) { + info.emplace_back(get_tpmi_select_info_1layer(channel, noise_variance)); } // Return invalid information. - return {}; + return {info}; } \ No newline at end of file diff --git a/tests/unittests/ran/pusch/pusch_tpmi_select_test.cpp b/tests/unittests/ran/pusch/pusch_tpmi_select_test.cpp index ba5965866d..170126b65d 100644 --- a/tests/unittests/ran/pusch/pusch_tpmi_select_test.cpp +++ b/tests/unittests/ran/pusch/pusch_tpmi_select_test.cpp @@ -109,7 +109,12 @@ TEST_P(PuschTpmiSelectFixture, VectorTest) // Get combined parameter. const test_case_t& test_case = GetParam(); - if ((test_case.channel_matrix.get_nof_rx_ports() > 1) || (test_case.channel_matrix.get_nof_tx_ports() > 2)) { + unsigned nof_tx_ports = test_case.channel_matrix.get_nof_tx_ports(); + unsigned nof_rx_ports = test_case.channel_matrix.get_nof_rx_ports(); + unsigned max_nof_layers = std::min(nof_tx_ports, nof_rx_ports); + + // Only one layer is currently supported. + if (max_nof_layers > 1) { GTEST_SKIP(); } diff --git a/tests/unittests/ran/pusch/pusch_tpmi_select_test_data.h b/tests/unittests/ran/pusch/pusch_tpmi_select_test_data.h index d3924120b2..d5ab4ed1ff 100644 --- a/tests/unittests/ran/pusch/pusch_tpmi_select_test_data.h +++ b/tests/unittests/ran/pusch/pusch_tpmi_select_test_data.h @@ -10,7 +10,7 @@ #pragma once -// This file was generated using the following MATLAB class on 15-02-2024 (seed 0): +// This file was generated using the following MATLAB class on 20-02-2024 (seed 0): // + "srsTPMISelectUnittest.m" #include "srsran/ran/pusch/pusch_tpmi_select.h" From 0b8843faf9031553191dcd8b73a8362b038b47d1 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Fri, 16 Feb 2024 13:40:53 +0100 Subject: [PATCH 107/140] sched: add tx power offsets to be propagated to PHY --- include/srsran/scheduler/scheduler_slot_handler.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/include/srsran/scheduler/scheduler_slot_handler.h b/include/srsran/scheduler/scheduler_slot_handler.h index 5db81a0f3b..c004e75eb9 100644 --- a/include/srsran/scheduler/scheduler_slot_handler.h +++ b/include/srsran/scheduler/scheduler_slot_handler.h @@ -57,7 +57,7 @@ struct pdsch_precoding_info { }; struct tx_power_pdcch_information { - // TODO + // TODO: populate power offsets required for PDCCH. }; struct dmrs_information { @@ -150,6 +150,14 @@ struct pdsch_codeword { bool new_data; }; +struct tx_power_pdsch_information { + /// Ratio of PDSCH EPRE to NZP CSI-RS EPRE when UE derives CSI feedback. See 3GPP TS 38.214, clause 5.2.2.3.1. Values + /// {-8,...,15} dB with 1 dB step size. + int8_t pwr_ctrl_offset; + /// Ratio of NZP CSI-RS EPRE to SSB/PBCH block EPRE. See 3GPP TS 38.214, clause 5.2.2.3.1. Values {-3, 0, 3, 6} dB. + int8_t pwr_ctrl_offset_ss; +}; + /// \brief Information relative to a PDSCH grant in a given slot. struct pdsch_information { rnti_t rnti; @@ -171,6 +179,7 @@ struct pdsch_information { harq_id_t harq_id; /// Precoding information for the PDSCH. This field is empty in case of 1-antenna port setups. optional precoding; + tx_power_pdsch_information tx_info; }; /// Dummy MAC CE payload. From a1a59cbd7c83db3e1f6996ba55f9c9eb82c026ca Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Fri, 1 Mar 2024 10:22:23 +0100 Subject: [PATCH 108/140] sched: populate power offset required to calculate profileNR --- lib/scheduler/support/sch_pdu_builder.cpp | 33 +++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/lib/scheduler/support/sch_pdu_builder.cpp b/lib/scheduler/support/sch_pdu_builder.cpp index f1a4b4e321..0e3240a6f9 100644 --- a/lib/scheduler/support/sch_pdu_builder.cpp +++ b/lib/scheduler/support/sch_pdu_builder.cpp @@ -428,6 +428,17 @@ void srsran::build_pdsch_f1_0_tc_rnti(pdsch_information& pdsch pdsch.harq_id = to_harq_id(dci_cfg.harq_process_number); pdsch.nof_layers = 1U; + // Populate power offsets. + if (not cell_cfg.nzp_csi_rs_list.empty()) { + // NOTE: Same powerControlOffset and powerControlOffsetSS is configured in NZP-CSI-RS-Resource across all resources. + pdsch.tx_info.pwr_ctrl_offset = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset; + // As per TS 38.213, clause 7.1.1, if powerControlOffsetSS is not provided to the UE, the UE assumes an offset of 0 + // dB. + pdsch.tx_info.pwr_ctrl_offset_ss = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.has_value() + ? *cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db + : 0; + } + // One Codeword. pdsch_codeword& cw = pdsch.codewords.emplace_back(); cw.new_data = is_new_data; @@ -479,6 +490,17 @@ void srsran::build_pdsch_f1_0_c_rnti(pdsch_information& pdsch, pdsch.n_id = get_pdsch_n_id(cell_cfg.pci, bwp_dl_ded, dci_dl_format::f1_0, ss_info.cfg->is_common_search_space()); pdsch.nof_layers = 1; + // Populate power offsets. + if (not cell_cfg.nzp_csi_rs_list.empty()) { + // NOTE: Same powerControlOffset and powerControlOffsetSS is configured in NZP-CSI-RS-Resource across all resources. + pdsch.tx_info.pwr_ctrl_offset = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset; + // As per TS 38.213, clause 7.1.1, if powerControlOffsetSS is not provided to the UE, the UE assumes an offset of 0 + // dB. + pdsch.tx_info.pwr_ctrl_offset_ss = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.has_value() + ? *cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db + : 0; + } + // One Codeword. pdsch_codeword& cw = pdsch.codewords.emplace_back(); cw.new_data = is_new_data; @@ -536,6 +558,17 @@ void srsran::build_pdsch_f1_1_c_rnti(pdsch_information& pdsch, // Beamforming and precoding. pdsch.precoding = cs_mgr.get_precoding(pdsch_cfg.nof_layers, prbs); + + // Populate power offsets. + if (not cell_cfg.nzp_csi_rs_list.empty()) { + // NOTE: Same powerControlOffset and powerControlOffsetSS is configured in NZP-CSI-RS-Resource across all resources. + pdsch.tx_info.pwr_ctrl_offset = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset; + // As per TS 38.213, clause 7.1.1, if powerControlOffsetSS is not provided to the UE, the UE assumes an offset of 0 + // dB. + pdsch.tx_info.pwr_ctrl_offset_ss = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.has_value() + ? *cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db + : 0; + } } void srsran::build_pusch_f0_0_tc_rnti(pusch_information& pusch, From 9fe49692e807ab5ed16de46a497e92095c19a45c Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Tue, 5 Mar 2024 15:00:31 +0100 Subject: [PATCH 109/140] sched: add tx power offsets required for PDCCH to be propagated to PHY --- include/srsran/scheduler/scheduler_slot_handler.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/srsran/scheduler/scheduler_slot_handler.h b/include/srsran/scheduler/scheduler_slot_handler.h index c004e75eb9..dea359dc4c 100644 --- a/include/srsran/scheduler/scheduler_slot_handler.h +++ b/include/srsran/scheduler/scheduler_slot_handler.h @@ -57,7 +57,8 @@ struct pdsch_precoding_info { }; struct tx_power_pdcch_information { - // TODO: populate power offsets required for PDCCH. + /// Ratio of NZP CSI-RS EPRE to SSB/PBCH block EPRE. See 3GPP TS 38.214, clause 5.2.2.3.1. Values {-3, 0, 3, 6} dB. + int8_t pwr_ctrl_offset_ss; }; struct dmrs_information { From d3cb9851f8724c1ae2ab72afa43c12ce72c1d6e6 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Tue, 5 Mar 2024 15:05:37 +0100 Subject: [PATCH 110/140] sched,fapi: remove mention of profileNR from variables in MAC --- include/srsran/scheduler/scheduler_slot_handler.h | 4 ++-- lib/fapi_adaptor/mac/mac_to_fapi_translator.cpp | 4 ++-- lib/scheduler/common_scheduling/csi_rs_scheduler.cpp | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/srsran/scheduler/scheduler_slot_handler.h b/include/srsran/scheduler/scheduler_slot_handler.h index dea359dc4c..fe4132945b 100644 --- a/include/srsran/scheduler/scheduler_slot_handler.h +++ b/include/srsran/scheduler/scheduler_slot_handler.h @@ -395,9 +395,9 @@ struct csi_rs_info { /// \brief ScramblingID of the CSI-RS as per 3GPP TS 38.214, sec 5.2.2.3.1. Values: {0,...,1023}. uint16_t scrambling_id; /// Ratio of PDSCH EPRE to NZP CSI-RS EPRE as per 3GPP TS 38.214, clause 5.2.2.3.1. Values: {-8,...,15}. - int8_t power_ctrl_offset_profile_nr; + int8_t power_ctrl_offset; /// Ratio of NZP CSI-RS EPRE to SSB/PBCH block EPRE. Values: {-3,0,3,6}. - int8_t power_ctrl_offset_ss_profile_nr; + int8_t power_ctrl_offset_ss; }; struct dl_sched_result { diff --git a/lib/fapi_adaptor/mac/mac_to_fapi_translator.cpp b/lib/fapi_adaptor/mac/mac_to_fapi_translator.cpp index 7e3461c173..d298ab2989 100644 --- a/lib/fapi_adaptor/mac/mac_to_fapi_translator.cpp +++ b/lib/fapi_adaptor/mac/mac_to_fapi_translator.cpp @@ -126,8 +126,8 @@ static void add_csi_rs_pdus_to_dl_request(fapi::dl_tti_request_message_builder& csi_builder.set_bwp_parameters(pdu.bwp_cfg->scs, pdu.bwp_cfg->cp); if (is_nzp_csi) { - csi_builder.set_tx_power_info_parameters(pdu.power_ctrl_offset_profile_nr, - to_nzp_csi_rs_epre_to_ssb(pdu.power_ctrl_offset_ss_profile_nr)); + csi_builder.set_tx_power_info_parameters(pdu.power_ctrl_offset, + to_nzp_csi_rs_epre_to_ssb(pdu.power_ctrl_offset_ss)); } else { // ZP-CSI type does not use these values. csi_builder.set_tx_power_info_parameters(0, fapi::nzp_csi_rs_epre_to_ssb::dB0); diff --git a/lib/scheduler/common_scheduling/csi_rs_scheduler.cpp b/lib/scheduler/common_scheduling/csi_rs_scheduler.cpp index 21e4e80ed6..b3ae32fd7b 100644 --- a/lib/scheduler/common_scheduling/csi_rs_scheduler.cpp +++ b/lib/scheduler/common_scheduling/csi_rs_scheduler.cpp @@ -47,9 +47,9 @@ static csi_rs_info build_csi_rs_info(const bwp_configuration& bwp_cfg, const nzp fill_csi_rs_info_res_map(csi_rs, nzp_csi_rs_res.res_mapping); - csi_rs.scrambling_id = nzp_csi_rs_res.scrambling_id; - csi_rs.power_ctrl_offset_profile_nr = nzp_csi_rs_res.pwr_ctrl_offset; - csi_rs.power_ctrl_offset_ss_profile_nr = + csi_rs.scrambling_id = nzp_csi_rs_res.scrambling_id; + csi_rs.power_ctrl_offset = nzp_csi_rs_res.pwr_ctrl_offset; + csi_rs.power_ctrl_offset_ss = nzp_csi_rs_res.pwr_ctrl_offset_ss_db.has_value() ? *nzp_csi_rs_res.pwr_ctrl_offset_ss_db : 0; return csi_rs; From f36afda46ad5fb3290e53dcbe7209a70079451db Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Wed, 6 Mar 2024 13:40:29 +0100 Subject: [PATCH 111/140] sched: propagate power offsets required for PDCCH and PDSCH to FAPI --- .../srsran/scheduler/scheduler_slot_handler.h | 11 ++-- .../pdcch_resource_allocator_impl.cpp | 8 +++ lib/scheduler/support/sch_pdu_builder.cpp | 57 +++++++++++++------ 3 files changed, 54 insertions(+), 22 deletions(-) diff --git a/include/srsran/scheduler/scheduler_slot_handler.h b/include/srsran/scheduler/scheduler_slot_handler.h index fe4132945b..e41b8d522b 100644 --- a/include/srsran/scheduler/scheduler_slot_handler.h +++ b/include/srsran/scheduler/scheduler_slot_handler.h @@ -58,7 +58,10 @@ struct pdsch_precoding_info { struct tx_power_pdcch_information { /// Ratio of NZP CSI-RS EPRE to SSB/PBCH block EPRE. See 3GPP TS 38.214, clause 5.2.2.3.1. Values {-3, 0, 3, 6} dB. - int8_t pwr_ctrl_offset_ss; + /// \remark If the UE has not been provided dedicated higher layer parameters, the UE may assume that the ratio of + /// PDCCH DMRS EPRE to SSS EPRE is within -8 dB and 8 dB when the UE monitors PDCCHs for a DCI format 1_0 with CRC + /// scrambled by SI-RNTI, P-RNTI, or RA-RNTI. See TS 38.213, clause 4.1. + int8_t pwr_ctrl_offset_ss{0}; }; struct dmrs_information { @@ -154,9 +157,9 @@ struct pdsch_codeword { struct tx_power_pdsch_information { /// Ratio of PDSCH EPRE to NZP CSI-RS EPRE when UE derives CSI feedback. See 3GPP TS 38.214, clause 5.2.2.3.1. Values /// {-8,...,15} dB with 1 dB step size. - int8_t pwr_ctrl_offset; + int8_t pwr_ctrl_offset{0}; /// Ratio of NZP CSI-RS EPRE to SSB/PBCH block EPRE. See 3GPP TS 38.214, clause 5.2.2.3.1. Values {-3, 0, 3, 6} dB. - int8_t pwr_ctrl_offset_ss; + int8_t pwr_ctrl_offset_ss{0}; }; /// \brief Information relative to a PDSCH grant in a given slot. @@ -180,7 +183,7 @@ struct pdsch_information { harq_id_t harq_id; /// Precoding information for the PDSCH. This field is empty in case of 1-antenna port setups. optional precoding; - tx_power_pdsch_information tx_info; + tx_power_pdsch_information tx_pwr_info; }; /// Dummy MAC CE payload. diff --git a/lib/scheduler/pdcch_scheduling/pdcch_resource_allocator_impl.cpp b/lib/scheduler/pdcch_scheduling/pdcch_resource_allocator_impl.cpp index 67ad4aae06..1073c92a1c 100644 --- a/lib/scheduler/pdcch_scheduling/pdcch_resource_allocator_impl.cpp +++ b/lib/scheduler/pdcch_scheduling/pdcch_resource_allocator_impl.cpp @@ -176,6 +176,10 @@ pdcch_ul_information* pdcch_resource_allocator_impl::alloc_ul_pdcch_helper(cell_ search_space_configuration::ue_specific_dci_format::f0_0_and_f1_0)) ? "0_0" : "0_1"; + // Populate power offsets. + if (not cell_cfg.nzp_csi_rs_list.empty() and cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.has_value()) { + pdcch.ctx.tx_pwr.pwr_ctrl_offset_ss = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.value(); + } // Allocate a position for UL PDCCH in CORESET. pdcch_slot_allocator& pdcch_alloc = get_pdcch_slot_alloc(slot_alloc.slot); @@ -219,6 +223,10 @@ pdcch_dl_information* pdcch_resource_allocator_impl::alloc_dl_pdcch_helper(cell_ search_space_configuration::ue_specific_dci_format::f0_0_and_f1_0)) ? "1_0" : "1_1"; + // Populate power offsets. + if (not cell_cfg.nzp_csi_rs_list.empty() and cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.has_value()) { + pdcch.ctx.tx_pwr.pwr_ctrl_offset_ss = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.value(); + } // Allocate a position for DL PDCCH in CORESET. pdcch_slot_allocator& pdcch_alloc = get_pdcch_slot_alloc(slot_alloc.slot); diff --git a/lib/scheduler/support/sch_pdu_builder.cpp b/lib/scheduler/support/sch_pdu_builder.cpp index 0e3240a6f9..ac06172133 100644 --- a/lib/scheduler/support/sch_pdu_builder.cpp +++ b/lib/scheduler/support/sch_pdu_builder.cpp @@ -311,6 +311,15 @@ void srsran::build_pdsch_f1_0_si_rnti(pdsch_information& pdsch pdsch.ss_set_type = dci_cfg.system_information_indicator == 0 ? search_space_set_type::type0 : search_space_set_type::type0A; pdsch.dci_fmt = dci_dl_format::f1_0; + + // Populate power offsets. + if (not cell_cfg.nzp_csi_rs_list.empty()) { + // NOTE: Same powerControlOffset and powerControlOffsetSS is configured in NZP-CSI-RS-Resource across all resources. + pdsch.tx_pwr_info.pwr_ctrl_offset = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset; + if (cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.has_value()) { + pdsch.tx_pwr_info.pwr_ctrl_offset_ss = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.value(); + } + } } void srsran::build_pdsch_f1_0_p_rnti(pdsch_information& pdsch, @@ -347,6 +356,15 @@ void srsran::build_pdsch_f1_0_p_rnti(pdsch_information& pdsch, pdsch.is_interleaved = dci_cfg.vrb_to_prb_mapping > 0; pdsch.ss_set_type = search_space_set_type::type2; pdsch.dci_fmt = dci_dl_format::f1_0; + + // Populate power offsets. + if (not cell_cfg.nzp_csi_rs_list.empty()) { + // NOTE: Same powerControlOffset and powerControlOffsetSS is configured in NZP-CSI-RS-Resource across all resources. + pdsch.tx_pwr_info.pwr_ctrl_offset = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset; + if (cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.has_value()) { + pdsch.tx_pwr_info.pwr_ctrl_offset_ss = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.value(); + } + } } void srsran::build_pdsch_f1_0_ra_rnti(pdsch_information& pdsch, @@ -388,6 +406,15 @@ void srsran::build_pdsch_f1_0_ra_rnti(pdsch_information& pdsch pdsch.is_interleaved = dci_cfg.vrb_to_prb_mapping > 0; pdsch.ss_set_type = search_space_set_type::type1; pdsch.dci_fmt = dci_dl_format::f1_0; + + // Populate power offsets. + if (not cell_cfg.nzp_csi_rs_list.empty()) { + // NOTE: Same powerControlOffset and powerControlOffsetSS is configured in NZP-CSI-RS-Resource across all resources. + pdsch.tx_pwr_info.pwr_ctrl_offset = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset; + if (cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.has_value()) { + pdsch.tx_pwr_info.pwr_ctrl_offset_ss = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.value(); + } + } } void srsran::build_pdsch_f1_0_tc_rnti(pdsch_information& pdsch, @@ -431,12 +458,10 @@ void srsran::build_pdsch_f1_0_tc_rnti(pdsch_information& pdsch // Populate power offsets. if (not cell_cfg.nzp_csi_rs_list.empty()) { // NOTE: Same powerControlOffset and powerControlOffsetSS is configured in NZP-CSI-RS-Resource across all resources. - pdsch.tx_info.pwr_ctrl_offset = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset; - // As per TS 38.213, clause 7.1.1, if powerControlOffsetSS is not provided to the UE, the UE assumes an offset of 0 - // dB. - pdsch.tx_info.pwr_ctrl_offset_ss = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.has_value() - ? *cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db - : 0; + pdsch.tx_pwr_info.pwr_ctrl_offset = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset; + if (cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.has_value()) { + pdsch.tx_pwr_info.pwr_ctrl_offset_ss = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.value(); + } } // One Codeword. @@ -493,12 +518,10 @@ void srsran::build_pdsch_f1_0_c_rnti(pdsch_information& pdsch, // Populate power offsets. if (not cell_cfg.nzp_csi_rs_list.empty()) { // NOTE: Same powerControlOffset and powerControlOffsetSS is configured in NZP-CSI-RS-Resource across all resources. - pdsch.tx_info.pwr_ctrl_offset = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset; - // As per TS 38.213, clause 7.1.1, if powerControlOffsetSS is not provided to the UE, the UE assumes an offset of 0 - // dB. - pdsch.tx_info.pwr_ctrl_offset_ss = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.has_value() - ? *cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db - : 0; + pdsch.tx_pwr_info.pwr_ctrl_offset = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset; + if (cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.has_value()) { + pdsch.tx_pwr_info.pwr_ctrl_offset_ss = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.value(); + } } // One Codeword. @@ -562,12 +585,10 @@ void srsran::build_pdsch_f1_1_c_rnti(pdsch_information& pdsch, // Populate power offsets. if (not cell_cfg.nzp_csi_rs_list.empty()) { // NOTE: Same powerControlOffset and powerControlOffsetSS is configured in NZP-CSI-RS-Resource across all resources. - pdsch.tx_info.pwr_ctrl_offset = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset; - // As per TS 38.213, clause 7.1.1, if powerControlOffsetSS is not provided to the UE, the UE assumes an offset of 0 - // dB. - pdsch.tx_info.pwr_ctrl_offset_ss = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.has_value() - ? *cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db - : 0; + pdsch.tx_pwr_info.pwr_ctrl_offset = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset; + if (cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.has_value()) { + pdsch.tx_pwr_info.pwr_ctrl_offset_ss = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.value(); + } } } From de1d08ef55740e3e3d4d6bb67ec50c4c06869ccc Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Wed, 6 Mar 2024 13:49:33 +0100 Subject: [PATCH 112/140] sched: add comments for transmit power information fields --- .../srsran/scheduler/scheduler_slot_handler.h | 8 +++++++- .../pdcch_resource_allocator_impl.cpp | 4 ++++ lib/scheduler/support/sch_pdu_builder.cpp | 18 ++++++++++++------ 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/include/srsran/scheduler/scheduler_slot_handler.h b/include/srsran/scheduler/scheduler_slot_handler.h index e41b8d522b..a34a6db900 100644 --- a/include/srsran/scheduler/scheduler_slot_handler.h +++ b/include/srsran/scheduler/scheduler_slot_handler.h @@ -56,11 +56,13 @@ struct pdsch_precoding_info { static_vector prg_infos; }; +/// Transmit power information associated with PDCCH PDU. struct tx_power_pdcch_information { /// Ratio of NZP CSI-RS EPRE to SSB/PBCH block EPRE. See 3GPP TS 38.214, clause 5.2.2.3.1. Values {-3, 0, 3, 6} dB. /// \remark If the UE has not been provided dedicated higher layer parameters, the UE may assume that the ratio of /// PDCCH DMRS EPRE to SSS EPRE is within -8 dB and 8 dB when the UE monitors PDCCHs for a DCI format 1_0 with CRC /// scrambled by SI-RNTI, P-RNTI, or RA-RNTI. See TS 38.213, clause 4.1. + /// \remark [Implementation-defined] In case UE is not configured with powerControlOffsetSS we assume it to be 0dB. int8_t pwr_ctrl_offset_ss{0}; }; @@ -154,11 +156,14 @@ struct pdsch_codeword { bool new_data; }; +/// Transmit power information associated with PDSCH PDU. struct tx_power_pdsch_information { /// Ratio of PDSCH EPRE to NZP CSI-RS EPRE when UE derives CSI feedback. See 3GPP TS 38.214, clause 5.2.2.3.1. Values /// {-8,...,15} dB with 1 dB step size. + /// \remark [Implementation-defined] In case UE is not configured with powerControlOffset we assume it to be 0dB. int8_t pwr_ctrl_offset{0}; /// Ratio of NZP CSI-RS EPRE to SSB/PBCH block EPRE. See 3GPP TS 38.214, clause 5.2.2.3.1. Values {-3, 0, 3, 6} dB. + /// \remark [Implementation-defined] In case UE is not configured with powerControlOffsetSS we assume it to be 0dB. int8_t pwr_ctrl_offset_ss{0}; }; @@ -183,7 +188,8 @@ struct pdsch_information { harq_id_t harq_id; /// Precoding information for the PDSCH. This field is empty in case of 1-antenna port setups. optional precoding; - tx_power_pdsch_information tx_pwr_info; + /// Transmit power information for the PDSCH. + tx_power_pdsch_information tx_pwr_info; }; /// Dummy MAC CE payload. diff --git a/lib/scheduler/pdcch_scheduling/pdcch_resource_allocator_impl.cpp b/lib/scheduler/pdcch_scheduling/pdcch_resource_allocator_impl.cpp index 1073c92a1c..73bd4c0963 100644 --- a/lib/scheduler/pdcch_scheduling/pdcch_resource_allocator_impl.cpp +++ b/lib/scheduler/pdcch_scheduling/pdcch_resource_allocator_impl.cpp @@ -178,6 +178,8 @@ pdcch_ul_information* pdcch_resource_allocator_impl::alloc_ul_pdcch_helper(cell_ : "0_1"; // Populate power offsets. if (not cell_cfg.nzp_csi_rs_list.empty() and cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.has_value()) { + // [Implementation-defined] It is assumed that same powerControlOffset and powerControlOffsetSS is configured in + // NZP-CSI-RS-Resource across all resources. pdcch.ctx.tx_pwr.pwr_ctrl_offset_ss = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.value(); } @@ -225,6 +227,8 @@ pdcch_dl_information* pdcch_resource_allocator_impl::alloc_dl_pdcch_helper(cell_ : "1_1"; // Populate power offsets. if (not cell_cfg.nzp_csi_rs_list.empty() and cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.has_value()) { + // [Implementation-defined] It is assumed that same powerControlOffset and powerControlOffsetSS is configured in + // NZP-CSI-RS-Resource across all resources. pdcch.ctx.tx_pwr.pwr_ctrl_offset_ss = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.value(); } diff --git a/lib/scheduler/support/sch_pdu_builder.cpp b/lib/scheduler/support/sch_pdu_builder.cpp index ac06172133..de2fcdaae9 100644 --- a/lib/scheduler/support/sch_pdu_builder.cpp +++ b/lib/scheduler/support/sch_pdu_builder.cpp @@ -314,7 +314,8 @@ void srsran::build_pdsch_f1_0_si_rnti(pdsch_information& pdsch // Populate power offsets. if (not cell_cfg.nzp_csi_rs_list.empty()) { - // NOTE: Same powerControlOffset and powerControlOffsetSS is configured in NZP-CSI-RS-Resource across all resources. + // [Implementation-defined] It is assumed that same powerControlOffset and powerControlOffsetSS is configured in + // NZP-CSI-RS-Resource across all resources. pdsch.tx_pwr_info.pwr_ctrl_offset = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset; if (cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.has_value()) { pdsch.tx_pwr_info.pwr_ctrl_offset_ss = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.value(); @@ -359,7 +360,8 @@ void srsran::build_pdsch_f1_0_p_rnti(pdsch_information& pdsch, // Populate power offsets. if (not cell_cfg.nzp_csi_rs_list.empty()) { - // NOTE: Same powerControlOffset and powerControlOffsetSS is configured in NZP-CSI-RS-Resource across all resources. + // [Implementation-defined] It is assumed that same powerControlOffset and powerControlOffsetSS is configured in + // NZP-CSI-RS-Resource across all resources. pdsch.tx_pwr_info.pwr_ctrl_offset = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset; if (cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.has_value()) { pdsch.tx_pwr_info.pwr_ctrl_offset_ss = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.value(); @@ -409,7 +411,8 @@ void srsran::build_pdsch_f1_0_ra_rnti(pdsch_information& pdsch // Populate power offsets. if (not cell_cfg.nzp_csi_rs_list.empty()) { - // NOTE: Same powerControlOffset and powerControlOffsetSS is configured in NZP-CSI-RS-Resource across all resources. + // [Implementation-defined] It is assumed that same powerControlOffset and powerControlOffsetSS is configured in + // NZP-CSI-RS-Resource across all resources. pdsch.tx_pwr_info.pwr_ctrl_offset = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset; if (cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.has_value()) { pdsch.tx_pwr_info.pwr_ctrl_offset_ss = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.value(); @@ -457,7 +460,8 @@ void srsran::build_pdsch_f1_0_tc_rnti(pdsch_information& pdsch // Populate power offsets. if (not cell_cfg.nzp_csi_rs_list.empty()) { - // NOTE: Same powerControlOffset and powerControlOffsetSS is configured in NZP-CSI-RS-Resource across all resources. + // [Implementation-defined] It is assumed that same powerControlOffset and powerControlOffsetSS is configured in + // NZP-CSI-RS-Resource across all resources. pdsch.tx_pwr_info.pwr_ctrl_offset = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset; if (cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.has_value()) { pdsch.tx_pwr_info.pwr_ctrl_offset_ss = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.value(); @@ -517,7 +521,8 @@ void srsran::build_pdsch_f1_0_c_rnti(pdsch_information& pdsch, // Populate power offsets. if (not cell_cfg.nzp_csi_rs_list.empty()) { - // NOTE: Same powerControlOffset and powerControlOffsetSS is configured in NZP-CSI-RS-Resource across all resources. + // [Implementation-defined] It is assumed that same powerControlOffset and powerControlOffsetSS is configured in + // NZP-CSI-RS-Resource across all resources. pdsch.tx_pwr_info.pwr_ctrl_offset = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset; if (cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.has_value()) { pdsch.tx_pwr_info.pwr_ctrl_offset_ss = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.value(); @@ -584,7 +589,8 @@ void srsran::build_pdsch_f1_1_c_rnti(pdsch_information& pdsch, // Populate power offsets. if (not cell_cfg.nzp_csi_rs_list.empty()) { - // NOTE: Same powerControlOffset and powerControlOffsetSS is configured in NZP-CSI-RS-Resource across all resources. + // [Implementation-defined] It is assumed that same powerControlOffset and powerControlOffsetSS is configured in + // NZP-CSI-RS-Resource across all resources. pdsch.tx_pwr_info.pwr_ctrl_offset = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset; if (cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.has_value()) { pdsch.tx_pwr_info.pwr_ctrl_offset_ss = cell_cfg.nzp_csi_rs_list.front().pwr_ctrl_offset_ss_db.value(); From 816ecf49978a01a48ec4abb24730b840c3fbce5b Mon Sep 17 00:00:00 2001 From: faluco Date: Tue, 5 Mar 2024 15:53:28 +0100 Subject: [PATCH 113/140] OFH: simplify logic in the RU timing notifier. While there, rename a method in slot symbol point to to_uint as the previous was confussing --- include/srsran/ofh/timing/slot_symbol_point.h | 6 ++-- lib/ofh/receiver/ofh_rx_window_checker.cpp | 4 +-- lib/ofh/transmitter/ofh_tx_window_checker.h | 2 +- lib/ru/ofh/ru_ofh_timing_notifier_impl.cpp | 33 +++---------------- lib/ru/ofh/ru_ofh_timing_notifier_impl.h | 13 ++++---- 5 files changed, 17 insertions(+), 41 deletions(-) diff --git a/include/srsran/ofh/timing/slot_symbol_point.h b/include/srsran/ofh/timing/slot_symbol_point.h index a4a9970a51..2c39cbbbe6 100644 --- a/include/srsran/ofh/timing/slot_symbol_point.h +++ b/include/srsran/ofh/timing/slot_symbol_point.h @@ -47,8 +47,8 @@ class slot_symbol_point /// Numerology index (0..4). unsigned get_numerology() const { return numerology; } - /// System slot. - uint32_t system_slot() const { return count_val; } + /// Conversion of slot symbol point to a raw counter. + uint32_t to_uint() const { return count_val; } /// Implementation of the sum operator, where \c jump is represented in number of symbols. slot_symbol_point& operator+=(int jump) @@ -141,7 +141,7 @@ inline int operator-(slot_symbol_point lhs, slot_symbol_point rhs) get_nof_slots_per_subframe(to_subcarrier_spacing(lhs.get_numerology())) * lhs.get_nof_symbols(); - int tmp = static_cast(lhs.system_slot()) - static_cast(rhs.system_slot()); + int tmp = static_cast(lhs.to_uint()) - static_cast(rhs.to_uint()); if (tmp > (nof_symbols_per_slot_wrap / 2)) { return (tmp - nof_symbols_per_slot_wrap); } diff --git a/lib/ofh/receiver/ofh_rx_window_checker.cpp b/lib/ofh/receiver/ofh_rx_window_checker.cpp index 8b940b9c47..cab38ad9b3 100644 --- a/lib/ofh/receiver/ofh_rx_window_checker.cpp +++ b/lib/ofh/receiver/ofh_rx_window_checker.cpp @@ -48,7 +48,7 @@ static int calculate_slot_symbol_point_distance(slot_symbol_point lhs, slot_symb get_nof_slots_per_subframe(to_subcarrier_spacing(rhs.get_numerology())) * rhs.get_nof_symbols(); - int a = static_cast(lhs.system_slot()) - static_cast(rhs.system_slot()); + int a = static_cast(lhs.to_uint()) - static_cast(rhs.to_uint()); if (a >= nof_symbols_per_slot_wrap / 2) { return a - nof_symbols_per_slot_wrap; } @@ -64,7 +64,7 @@ void rx_window_checker::on_new_symbol(slot_symbol_point symbol_point) slot_symbol_point ota_symbol_point = calculate_ofh_slot_symbol_point(symbol_point); // Update the stored slot symbol point as system value. - count_val.store(ota_symbol_point.system_slot(), std::memory_order_release); + count_val.store(ota_symbol_point.to_uint(), std::memory_order_release); // Print the statistics. print_statistics(); diff --git a/lib/ofh/transmitter/ofh_tx_window_checker.h b/lib/ofh/transmitter/ofh_tx_window_checker.h index 16d9961b5d..72c506e21e 100644 --- a/lib/ofh/transmitter/ofh_tx_window_checker.h +++ b/lib/ofh/transmitter/ofh_tx_window_checker.h @@ -35,7 +35,7 @@ class tx_window_checker : public ota_symbol_boundary_notifier void on_new_symbol(slot_symbol_point symbol_point) override { // This atomic is only written from a single thread. - count_val.store(symbol_point.system_slot(), std::memory_order::memory_order_release); + count_val.store(symbol_point.to_uint(), std::memory_order::memory_order_release); } /// Returns true if the given slot is already late compared to the current OTA time, otherwise false. diff --git a/lib/ru/ofh/ru_ofh_timing_notifier_impl.cpp b/lib/ru/ofh/ru_ofh_timing_notifier_impl.cpp index 4c96e08547..87a3298f65 100644 --- a/lib/ru/ofh/ru_ofh_timing_notifier_impl.cpp +++ b/lib/ru/ofh/ru_ofh_timing_notifier_impl.cpp @@ -13,28 +13,8 @@ using namespace srsran; -void ru_ofh_timing_notifier_impl::notify_new_slot(ofh::slot_symbol_point symbol_point) -{ - // For the first slot, update the current_slot member and return. - // Returning at this point will notify the upper layers on the next slot, instead of notifying a random one. - if (!current_slot.valid()) { - current_slot = symbol_point.get_slot(); - return; - } - - // Nothing to do if the slot did not change. - if (symbol_point.get_slot() == current_slot) { - return; - } - - current_slot = symbol_point.get_slot(); - timing_notifier.on_tti_boundary(current_slot + nof_slot_offset_du_ru); -} - void ru_ofh_timing_notifier_impl::on_new_symbol(ofh::slot_symbol_point symbol_point) { - notify_new_slot(symbol_point); - if (symbol_point.get_symbol_index() == half_slot_symbol) { timing_notifier.on_ul_half_slot_boundary(symbol_point.get_slot()); } @@ -42,14 +22,9 @@ void ru_ofh_timing_notifier_impl::on_new_symbol(ofh::slot_symbol_point symbol_po if (symbol_point.get_symbol_index() == full_slot_symbol) { timing_notifier.on_ul_full_slot_boundary(symbol_point.get_slot()); } -} -ru_ofh_timing_notifier_impl::ru_ofh_timing_notifier_impl(unsigned nof_slot_offset_du_ru_, - unsigned nof_symbols_per_slot, - ru_timing_notifier& timing_notifier_) : - nof_slot_offset_du_ru(nof_slot_offset_du_ru_), - half_slot_symbol(nof_symbols_per_slot / 2U - 1U), - full_slot_symbol(nof_symbols_per_slot - 1U), - timing_notifier(timing_notifier_) -{ + // New slots start on symbol index 0. + if (symbol_point.get_symbol_index() == 0) { + timing_notifier.on_tti_boundary(symbol_point.get_slot() + nof_slot_offset_du_ru); + } } diff --git a/lib/ru/ofh/ru_ofh_timing_notifier_impl.h b/lib/ru/ofh/ru_ofh_timing_notifier_impl.h index f6f22ca8b9..bb24097f38 100644 --- a/lib/ru/ofh/ru_ofh_timing_notifier_impl.h +++ b/lib/ru/ofh/ru_ofh_timing_notifier_impl.h @@ -23,21 +23,22 @@ class ru_ofh_timing_notifier_impl : public ofh::ota_symbol_boundary_notifier public: ru_ofh_timing_notifier_impl(unsigned nof_slot_offset_du_ru_, unsigned nof_symbols_per_slot, - ru_timing_notifier& timing_notifier_); + ru_timing_notifier& timing_notifier_) : + nof_slot_offset_du_ru(nof_slot_offset_du_ru_), + half_slot_symbol(nof_symbols_per_slot / 2U - 1U), + full_slot_symbol(nof_symbols_per_slot - 1U), + timing_notifier(timing_notifier_) + { + } // See interface for documentation. void on_new_symbol(ofh::slot_symbol_point symbol_point) override; -private: - /// Notifies a new slot. - void notify_new_slot(ofh::slot_symbol_point symbol_point); - private: const unsigned nof_slot_offset_du_ru; const unsigned half_slot_symbol; const unsigned full_slot_symbol; ru_timing_notifier& timing_notifier; - slot_point current_slot; }; } // namespace srsran From 7df580954bd72ac9546279d56dcf34f79314e392 Mon Sep 17 00:00:00 2001 From: faluco Date: Tue, 5 Mar 2024 18:17:09 +0100 Subject: [PATCH 114/140] ofh: relax use of rx window checker to be only used when the rx statistics are enabled, otherwise do nothing on it --- include/srsran/ofh/receiver/ofh_receiver.h | 4 +-- lib/ofh/receiver/ofh_receiver_impl.cpp | 4 +-- lib/ofh/receiver/ofh_receiver_impl.h | 2 +- lib/ofh/receiver/ofh_rx_window_checker.cpp | 19 ++++++---- lib/ofh/receiver/ofh_rx_window_checker.h | 24 ++++++++----- lib/ru/ofh/ru_ofh_impl.cpp | 4 ++- .../receiver/ofh_rx_window_checker_test.cpp | 36 ++++++++++++++----- 7 files changed, 62 insertions(+), 31 deletions(-) diff --git a/include/srsran/ofh/receiver/ofh_receiver.h b/include/srsran/ofh/receiver/ofh_receiver.h index ec2e7c8f85..baed964a94 100644 --- a/include/srsran/ofh/receiver/ofh_receiver.h +++ b/include/srsran/ofh/receiver/ofh_receiver.h @@ -23,8 +23,8 @@ class receiver public: virtual ~receiver() = default; - /// Returns the OTA symbol boundary notifier of this Open Fronthaul receiver. - virtual ota_symbol_boundary_notifier& get_ota_symbol_boundary_notifier() = 0; + /// Returns an OTA symbol boundary notifier of this Open Fronthaul receiver or nullptr if not present. + virtual ota_symbol_boundary_notifier* get_ota_symbol_boundary_notifier() = 0; /// Returns the controller of this Open Fronthaul receiver. virtual controller& get_controller() = 0; diff --git a/lib/ofh/receiver/ofh_receiver_impl.cpp b/lib/ofh/receiver/ofh_receiver_impl.cpp index d939fd39ca..9b29f7f387 100644 --- a/lib/ofh/receiver/ofh_receiver_impl.cpp +++ b/lib/ofh/receiver/ofh_receiver_impl.cpp @@ -64,9 +64,9 @@ receiver_impl::receiver_impl(const receiver_config& config, receiver_impl_depend { } -ota_symbol_boundary_notifier& receiver_impl::get_ota_symbol_boundary_notifier() +ota_symbol_boundary_notifier* receiver_impl::get_ota_symbol_boundary_notifier() { - return window_checker; + return window_checker.disabled() ? nullptr : &window_checker; } controller& receiver_impl::get_controller() diff --git a/lib/ofh/receiver/ofh_receiver_impl.h b/lib/ofh/receiver/ofh_receiver_impl.h index 1fcb21ff9f..c55ff87415 100644 --- a/lib/ofh/receiver/ofh_receiver_impl.h +++ b/lib/ofh/receiver/ofh_receiver_impl.h @@ -49,7 +49,7 @@ class receiver_impl : public receiver receiver_impl(const receiver_config& config, receiver_impl_dependencies&& dependencies); // See interface for documentation. - ota_symbol_boundary_notifier& get_ota_symbol_boundary_notifier() override; + ota_symbol_boundary_notifier* get_ota_symbol_boundary_notifier() override; // See interface for documentation. controller& get_controller() override; diff --git a/lib/ofh/receiver/ofh_rx_window_checker.cpp b/lib/ofh/receiver/ofh_rx_window_checker.cpp index cab38ad9b3..9ddc8307d3 100644 --- a/lib/ofh/receiver/ofh_rx_window_checker.cpp +++ b/lib/ofh/receiver/ofh_rx_window_checker.cpp @@ -20,6 +20,7 @@ rx_window_checker::rx_window_checker(srslog::basic_logger& lo std::chrono::duration symbol_duration) : timing_parameters(params), nof_symbols_in_one_second(std::ceil(std::chrono::seconds(1) / symbol_duration)), + is_disabled(!is_log_enabled(logger_)), nof_symbols(0), statistics(logger_) { @@ -60,6 +61,10 @@ static int calculate_slot_symbol_point_distance(slot_symbol_point lhs, slot_symb void rx_window_checker::on_new_symbol(slot_symbol_point symbol_point) { + if (SRSRAN_LIKELY(is_disabled)) { + return; + } + // Build a new slot symbol point that manages that the SFN values in OFH is 1 byte. slot_symbol_point ota_symbol_point = calculate_ofh_slot_symbol_point(symbol_point); @@ -70,8 +75,12 @@ void rx_window_checker::on_new_symbol(slot_symbol_point symbol_point) print_statistics(); } -bool rx_window_checker::update_rx_window_statistics(slot_symbol_point symbol_point) +void rx_window_checker::update_rx_window_statistics(slot_symbol_point symbol_point) { + if (SRSRAN_LIKELY(is_disabled)) { + return; + } + // Store the ota symbol point to use the same value for the early and late points. slot_symbol_point ota_point( symbol_point.get_numerology(), count_val.load(std::memory_order_acquire), symbol_point.get_nof_symbols()); @@ -82,21 +91,17 @@ bool rx_window_checker::update_rx_window_statistics(slot_symbol_point symbol_poi // Late detected. if (diff > static_cast(timing_parameters.sym_end)) { statistics.increment_late_counter(); - - return false; + return; } // Early detected. if (diff < static_cast(timing_parameters.sym_start)) { statistics.increment_early_counter(); - - return false; + return; } // On time detected. statistics.increment_on_time_counter(); - - return true; } void rx_window_checker::print_statistics() diff --git a/lib/ofh/receiver/ofh_rx_window_checker.h b/lib/ofh/receiver/ofh_rx_window_checker.h index df63de9059..ca10e9330b 100644 --- a/lib/ofh/receiver/ofh_rx_window_checker.h +++ b/lib/ofh/receiver/ofh_rx_window_checker.h @@ -53,6 +53,13 @@ class rx_window_checker : public ota_symbol_boundary_notifier uint64_t nof_late_messages() const { return late_counter.load(std::memory_order_relaxed); } }; + const rx_window_timing_parameters timing_parameters; + const unsigned nof_symbols_in_one_second; + const bool is_disabled; + unsigned nof_symbols; + rx_window_checker_statistics statistics; + std::atomic count_val; + public: rx_window_checker(srslog::basic_logger& logger_, const rx_window_timing_parameters& params, @@ -61,8 +68,11 @@ class rx_window_checker : public ota_symbol_boundary_notifier // See interface for documentation. void on_new_symbol(slot_symbol_point symbol_point) override; - /// Returns true if the given symbol point is within the reception window, otherwise false. - bool update_rx_window_statistics(slot_symbol_point symbol_point); + /// Returns true if the Rx window checker is disabled, otherwise returns false. + bool disabled() const { return is_disabled; } + + /// Updates the Rx window statistics. + void update_rx_window_statistics(slot_symbol_point symbol_point); /// Getters to the number of messages. uint64_t nof_on_time_messages() const { return statistics.nof_on_time_messages(); } @@ -70,15 +80,11 @@ class rx_window_checker : public ota_symbol_boundary_notifier uint64_t nof_late_messages() const { return statistics.nof_late_messages(); } private: + /// Returns true if the given logger is enabled for info level, otherwise false. + static bool is_log_enabled(srslog::basic_logger& logger) { return logger.info.enabled(); } + /// Prints the statistics every second. void print_statistics(); - -private: - const rx_window_timing_parameters timing_parameters; - const unsigned nof_symbols_in_one_second; - unsigned nof_symbols; - rx_window_checker_statistics statistics; - std::atomic count_val; }; } // namespace ofh diff --git a/lib/ru/ofh/ru_ofh_impl.cpp b/lib/ru/ofh/ru_ofh_impl.cpp index 6da31992f1..e213873583 100644 --- a/lib/ru/ofh/ru_ofh_impl.cpp +++ b/lib/ru/ofh/ru_ofh_impl.cpp @@ -62,7 +62,9 @@ ru_ofh_impl::ru_ofh_impl(const ru_ofh_impl_config& config, ru_ofh_impl_dependenc // Add the sectors notifiers. for (auto& sector : sectors) { notifiers.push_back(§or->get_transmitter().get_ota_symbol_boundary_notifier()); - notifiers.push_back(§or->get_receiver().get_ota_symbol_boundary_notifier()); + if (auto* notifier = sector->get_receiver().get_ota_symbol_boundary_notifier()) { + notifiers.push_back(notifier); + } // Configure the error handler for the OFH sectors. sector->set_error_notifier(error_handler); diff --git a/tests/unittests/ofh/receiver/ofh_rx_window_checker_test.cpp b/tests/unittests/ofh/receiver/ofh_rx_window_checker_test.cpp index aa8d519964..f132f20806 100644 --- a/tests/unittests/ofh/receiver/ofh_rx_window_checker_test.cpp +++ b/tests/unittests/ofh/receiver/ofh_rx_window_checker_test.cpp @@ -21,9 +21,11 @@ TEST(ofh_rx_window_checker, on_time_packet_counts_one_packet) subcarrier_spacing scs = subcarrier_spacing::kHz30; std::chrono::duration symbol_duration( std::chrono::duration(1e6 / (nof_symbols_per_slot * get_nof_slots_per_subframe(scs)))); + auto& logger = srslog::fetch_basic_logger("TEST"); + logger.set_level(srslog::basic_levels::info); // Create window checker with timing parameters corresponding to Ta4_min=50us, Ta4_max=300us. - rx_window_checker rx_window(srslog::fetch_basic_logger("TEST"), {2, 9}, symbol_duration); + rx_window_checker rx_window(logger, {2, 9}, symbol_duration); // Create the OTA notification. slot_symbol_point ota_slot({1, 1, 1, 1}, 7, 14); @@ -40,12 +42,14 @@ TEST(ofh_rx_window_checker, packet_on_the_window_start_count_as_valid) { unsigned nof_symbols_per_slot = 14; subcarrier_spacing scs = subcarrier_spacing::kHz30; + auto& logger = srslog::fetch_basic_logger("TEST"); + logger.set_level(srslog::basic_levels::info); std::chrono::duration symbol_duration( std::chrono::duration(1e6 / (nof_symbols_per_slot * get_nof_slots_per_subframe(scs)))); // Create window checker with timing parameters corresponding to Ta4_min=50us, Ta4_max=300us. - rx_window_checker rx_window(srslog::fetch_basic_logger("TEST"), {2, 9}, symbol_duration); + rx_window_checker rx_window(logger, {2, 9}, symbol_duration); // Create the OTA notification. slot_symbol_point ota_slot({1, 1, 1, 1}, 7, 14); @@ -62,12 +66,14 @@ TEST(ofh_rx_window_checker, packet_on_the_window_end_count_as_valid) { unsigned nof_symbols_per_slot = 14; subcarrier_spacing scs = subcarrier_spacing::kHz30; + auto& logger = srslog::fetch_basic_logger("TEST"); + logger.set_level(srslog::basic_levels::info); std::chrono::duration symbol_duration( std::chrono::duration(1e6 / (nof_symbols_per_slot * get_nof_slots_per_subframe(scs)))); // Create window checker with timing parameters corresponding to Ta4_min=50us, Ta4_max=510us. - rx_window_checker rx_window(srslog::fetch_basic_logger("TEST"), {2, 15}, symbol_duration); + rx_window_checker rx_window(logger, {2, 15}, symbol_duration); // Create the OTA notification. slot_symbol_point ota_slot({1, 1, 1, 1}, 7, 14); @@ -84,12 +90,14 @@ TEST(ofh_rx_window_checker, early_packet_counts_one_packet) { unsigned nof_symbols_per_slot = 14; subcarrier_spacing scs = subcarrier_spacing::kHz30; + auto& logger = srslog::fetch_basic_logger("TEST"); + logger.set_level(srslog::basic_levels::info); std::chrono::duration symbol_duration( std::chrono::duration(1e6 / (nof_symbols_per_slot * get_nof_slots_per_subframe(scs)))); // Create window checker with timing parameters corresponding to Ta4_min=80us, Ta4_max=300us. - rx_window_checker rx_window(srslog::fetch_basic_logger("TEST"), {3, 9}, symbol_duration); + rx_window_checker rx_window(logger, {3, 9}, symbol_duration); // Create the OTA notification. slot_symbol_point ota_slot({1, 1, 1, 1}, 7, 14); @@ -106,12 +114,14 @@ TEST(ofh_rx_window_checker, late_packet_counts_one_packet) { unsigned nof_symbols_per_slot = 14; subcarrier_spacing scs = subcarrier_spacing::kHz30; + auto& logger = srslog::fetch_basic_logger("TEST"); + logger.set_level(srslog::basic_levels::info); std::chrono::duration symbol_duration( std::chrono::duration(1e6 / (nof_symbols_per_slot * get_nof_slots_per_subframe(scs)))); // Create window checker with timing parameters corresponding to Ta4_min=50us, Ta4_max=300us. - rx_window_checker rx_window(srslog::fetch_basic_logger("TEST"), {2, 9}, symbol_duration); + rx_window_checker rx_window(logger, {2, 9}, symbol_duration); // Create the OTA notification. slot_symbol_point ota_slot({1, 1, 1, 1}, 7, 14); @@ -128,12 +138,14 @@ TEST(ofh_rx_window_checker, window_change_slot_works) { unsigned nof_symbols_per_slot = 14; subcarrier_spacing scs = subcarrier_spacing::kHz30; + auto& logger = srslog::fetch_basic_logger("TEST"); + logger.set_level(srslog::basic_levels::info); std::chrono::duration symbol_duration( std::chrono::duration(1e6 / (nof_symbols_per_slot * get_nof_slots_per_subframe(scs)))); // Create window checker with timing parameters corresponding to Ta4_min=50us, Ta4_max=300us. - rx_window_checker rx_window(srslog::fetch_basic_logger("TEST"), {2, 9}, symbol_duration); + rx_window_checker rx_window(logger, {2, 9}, symbol_duration); // Create the OTA notification. slot_symbol_point ota_slot({1, 1, 1, 0}, 1, 14); @@ -150,12 +162,14 @@ TEST(ofh_rx_window_checker, window_change_sfn_works) { unsigned nof_symbols_per_slot = 14; subcarrier_spacing scs = subcarrier_spacing::kHz30; + auto& logger = srslog::fetch_basic_logger("TEST"); + logger.set_level(srslog::basic_levels::info); std::chrono::duration symbol_duration( std::chrono::duration(1e6 / (nof_symbols_per_slot * get_nof_slots_per_subframe(scs)))); // Create window checker with timing parameters corresponding to Ta4_min=50us, Ta4_max=300us. - rx_window_checker rx_window(srslog::fetch_basic_logger("TEST"), {2, 9}, symbol_duration); + rx_window_checker rx_window(logger, {2, 9}, symbol_duration); // Create the OTA notification. slot_symbol_point ota_slot({1, 1, 0, 0}, 1, 14); @@ -172,12 +186,14 @@ TEST(ofh_rx_window_checker, window_change_sfn_byte_works) { unsigned nof_symbols_per_slot = 14; subcarrier_spacing scs = subcarrier_spacing::kHz30; + auto& logger = srslog::fetch_basic_logger("TEST"); + logger.set_level(srslog::basic_levels::info); std::chrono::duration symbol_duration( std::chrono::duration(1e6 / (nof_symbols_per_slot * get_nof_slots_per_subframe(scs)))); // Create window checker with timing parameters corresponding to Ta4_min=50us, Ta4_max=300us. - rx_window_checker rx_window(srslog::fetch_basic_logger("TEST"), {2, 9}, symbol_duration); + rx_window_checker rx_window(logger, {2, 9}, symbol_duration); // Create the OTA notification. slot_symbol_point ota_slot({1, 0, 0, 0}, 1, 14); @@ -194,12 +210,14 @@ TEST(ofh_rx_window_checker, window_change_sfn_byte_and_message_is_in_sfn_0) { unsigned nof_symbols_per_slot = 14; subcarrier_spacing scs = subcarrier_spacing::kHz30; + auto& logger = srslog::fetch_basic_logger("TEST"); + logger.set_level(srslog::basic_levels::info); std::chrono::duration symbol_duration( std::chrono::duration(1e6 / (nof_symbols_per_slot * get_nof_slots_per_subframe(scs)))); // Create window checker with timing parameters corresponding to Ta4_min=50us, Ta4_max=300us. - rx_window_checker rx_window(srslog::fetch_basic_logger("TEST"), {2, 9}, symbol_duration); + rx_window_checker rx_window(logger, {2, 9}, symbol_duration); // Create the OTA notification. slot_symbol_point ota_slot({1, 0, 0, 0}, 3, 14); From c763ec7d16c67c5cc760c58ca527a5a9ef9e4f14 Mon Sep 17 00:00:00 2001 From: asaezper Date: Thu, 7 Mar 2024 11:53:23 +0100 Subject: [PATCH 115/140] ci: change amarisoft version --- .gitlab/ci/e2e/.env | 4 ++-- .gitlab/ci/trx.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index b6ac009879..fa24f2da95 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -1,8 +1,8 @@ SRSGNB_REGISTRY_URI=registry.gitlab.com/softwareradiosystems/srsgnb RETINA_REGISTRY_PREFIX=registry.gitlab.com/softwareradiosystems/ci/retina -RETINA_VERSION=0.44.1 +RETINA_VERSION=0.44.2 UBUNTU_VERSION=24.04 -AMARISOFT_VERSION=2024-02-20 +AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11 OPEN5GS_VERSION=2.6.6 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin diff --git a/.gitlab/ci/trx.yml b/.gitlab/ci/trx.yml index 536d9bc824..572387c292 100644 --- a/.gitlab/ci/trx.yml +++ b/.gitlab/ci/trx.yml @@ -19,7 +19,7 @@ build trx driver: extends: .build_and_unit variables: AMARISOFT_PACKAGE_REGISTRY: ${CI_API_V4_URL}/projects/44296988/packages/generic/amarisoft - AMARISOFT_VERSION: "2024-02-20" + AMARISOFT_VERSION: "2023-09-08" KUBERNETES_CPU_REQUEST: 2 KUBERNETES_CPU_LIMIT: 2 KUBERNETES_MEMORY_REQUEST: 2.5Gi From 1aa1618274d9ddd8767f9e0d053bb0298014f610 Mon Sep 17 00:00:00 2001 From: asaezper Date: Thu, 7 Mar 2024 11:53:40 +0100 Subject: [PATCH 116/140] ci,e2e: disable mac pcap on 32 ue tests --- .gitlab/ci/e2e.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index b6c313520e..a5087ba38b 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -237,7 +237,7 @@ amari 1UE: TESTBED: "zmq_single_ue" MARKERS: "zmq_single_ue" E2E_LOG_LEVEL: "info" - RETINA_ARGS: "gnb.all.pcap=True gnb.all.mac_enable=True gnb.all.rlc_enable=True" + RETINA_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=True" needs: - job: "basic relwithdeb" artifacts: true From e54f99157eaea693c7091c0557b7c8ea93bc1d33 Mon Sep 17 00:00:00 2001 From: asaezper Date: Thu, 7 Mar 2024 12:57:03 +0100 Subject: [PATCH 117/140] ci,e2e: restore hw tests --- .gitlab/ci/e2e.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index a5087ba38b..afa63823c0 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -455,8 +455,6 @@ test mode ru memcheck: amari b200 asan: extends: .rf - when: manual - allow_failure: true variables: MARKERS: "rf_not_crash" needs: @@ -466,15 +464,11 @@ amari b200 asan: validate b200 config: extends: .rf - when: manual - allow_failure: true variables: MARKERS: "rf_b200" validate n300 config: extends: .rf - when: manual - allow_failure: true variables: MARKERS: "rf_n300" TESTBED: "android_n300" @@ -500,8 +494,6 @@ android b200: android x300: stage: rf extends: .e2e-run - when: manual - allow_failure: true variables: GROUP: "rf" TESTBED: "android_x300" From a88d0dd01292e4b571f3d2a9f1d6a1f00ec0b36e Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Thu, 29 Feb 2024 09:32:09 +0100 Subject: [PATCH 118/140] du: refactor includes --- include/srsran/f1u/du/f1u_gateway.h | 1 - lib/du_manager/du_ue/du_bearer.cpp | 1 - tests/benchmarks/du_high/du_high_benchmark.cpp | 2 +- tests/unittests/du_manager/du_manager_test_helpers.cpp | 1 + tests/unittests/du_manager/du_manager_test_helpers.h | 4 ++-- tests/unittests/du_manager/du_ue/du_bearer_test.cpp | 1 + .../procedures/du_manager_procedure_test_helpers.h | 5 +++-- .../procedures/du_ue_ric_configuration_procedure_test.cpp | 3 ++- 8 files changed, 10 insertions(+), 8 deletions(-) diff --git a/include/srsran/f1u/du/f1u_gateway.h b/include/srsran/f1u/du/f1u_gateway.h index 3ee0ece094..579d8b2427 100644 --- a/include/srsran/f1u/du/f1u_gateway.h +++ b/include/srsran/f1u/du/f1u_gateway.h @@ -13,7 +13,6 @@ #include "srsran/f1u/du/f1u_bearer.h" #include "srsran/f1u/du/f1u_config.h" #include "srsran/f1u/du/f1u_rx_sdu_notifier.h" -#include "srsran/gtpu/gtpu_teid.h" #include "srsran/ran/lcid.h" #include "srsran/ran/up_transport_layer_info.h" #include "srsran/support/timers.h" diff --git a/lib/du_manager/du_ue/du_bearer.cpp b/lib/du_manager/du_ue/du_bearer.cpp index a85ebbf39a..161d17f049 100644 --- a/lib/du_manager/du_ue/du_bearer.cpp +++ b/lib/du_manager/du_ue/du_bearer.cpp @@ -10,7 +10,6 @@ #include "du_bearer.h" #include "../converters/rlc_config_helpers.h" -#include "srsran/adt/static_vector.h" #include "srsran/du_manager/du_manager_params.h" #include "srsran/gtpu/gtpu_teid_pool.h" diff --git a/tests/benchmarks/du_high/du_high_benchmark.cpp b/tests/benchmarks/du_high/du_high_benchmark.cpp index 286f5afdd4..7f84adc10c 100644 --- a/tests/benchmarks/du_high/du_high_benchmark.cpp +++ b/tests/benchmarks/du_high/du_high_benchmark.cpp @@ -29,8 +29,8 @@ #include "lib/du_high/du_high_executor_strategies.h" #include "lib/du_high/du_high_impl.h" +#include "lib/mac/mac_ul/ul_bsr.h" #include "tests/unittests/f1ap/du/f1ap_du_test_helpers.h" -#include "tests/unittests/mac/mac_test_helpers.h" #include "srsran/asn1/f1ap/common.h" #include "srsran/du/du_cell_config_helpers.h" #include "srsran/du_high/du_high_configuration.h" diff --git a/tests/unittests/du_manager/du_manager_test_helpers.cpp b/tests/unittests/du_manager/du_manager_test_helpers.cpp index 4588ecfa6c..6f3917418d 100644 --- a/tests/unittests/du_manager/du_manager_test_helpers.cpp +++ b/tests/unittests/du_manager/du_manager_test_helpers.cpp @@ -9,6 +9,7 @@ */ #include "du_manager_test_helpers.h" +#include "srsran/du/du_cell_config_helpers.h" #include "srsran/mac/config/mac_cell_group_config_factory.h" #include "srsran/mac/config/mac_config_helpers.h" #include "srsran/rlc/rlc_srb_config_factory.h" diff --git a/tests/unittests/du_manager/du_manager_test_helpers.h b/tests/unittests/du_manager/du_manager_test_helpers.h index 3806eb7ddd..143fc3d00d 100644 --- a/tests/unittests/du_manager/du_manager_test_helpers.h +++ b/tests/unittests/du_manager/du_manager_test_helpers.h @@ -10,9 +10,9 @@ #pragma once -#include "lib/du_manager/du_ue/du_ue_manager_repository.h" -#include "srsran/du/du_cell_config_helpers.h" +#include "lib/du_manager/ran_resource_management/du_ran_resource_manager.h" #include "srsran/du_manager/du_manager_params.h" +#include "srsran/gtpu/gtpu_teid_pool.h" #include "srsran/support/async/async_test_utils.h" #include "srsran/support/executors/manual_task_worker.h" #include diff --git a/tests/unittests/du_manager/du_ue/du_bearer_test.cpp b/tests/unittests/du_manager/du_ue/du_bearer_test.cpp index fe1e0c08a7..f42586f768 100644 --- a/tests/unittests/du_manager/du_ue/du_bearer_test.cpp +++ b/tests/unittests/du_manager/du_ue/du_bearer_test.cpp @@ -9,6 +9,7 @@ */ #include "lib/du_manager/du_ue/du_bearer.h" +#include "lib/du_manager/du_ue/du_ue_bearer_manager.h" #include "tests/unittests/du_manager/du_manager_test_helpers.h" #include "srsran/du/du_cell_config_helpers.h" #include "srsran/support/test_utils.h" diff --git a/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.h b/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.h index d66285e6c0..cbc335d69d 100644 --- a/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.h +++ b/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.h @@ -11,7 +11,8 @@ #pragma once #include "../du_manager_test_helpers.h" -#include "srsran/mac/config/mac_cell_group_config_factory.h" +#include "lib/du_manager/du_ue/du_ue.h" +#include "lib/du_manager/du_ue/du_ue_manager_repository.h" #include "srsran/support/async/fifo_async_task_scheduler.h" namespace srsran { @@ -115,4 +116,4 @@ class du_manager_proc_tester : public du_manager_test_bench }; } // namespace srs_du -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/tests/unittests/du_manager/procedures/du_ue_ric_configuration_procedure_test.cpp b/tests/unittests/du_manager/procedures/du_ue_ric_configuration_procedure_test.cpp index b06e317df0..e1487ba58a 100644 --- a/tests/unittests/du_manager/procedures/du_ue_ric_configuration_procedure_test.cpp +++ b/tests/unittests/du_manager/procedures/du_ue_ric_configuration_procedure_test.cpp @@ -10,6 +10,7 @@ #include "du_manager_procedure_test_helpers.h" #include "lib/du_manager/procedures/du_ue_ric_configuration_procedure.h" +#include "srsran/du/du_cell_config_helpers.h" #include "srsran/support/test_utils.h" #include @@ -98,4 +99,4 @@ TEST_F(du_ue_ric_config_tester, mac.wait_ue_reconf.result = mac_ue_reconfiguration_response{test_ue->ue_index, true}; mac.wait_ue_reconf.ready_ev.set(); ASSERT_TRUE(proc_result().has_value()) << "The procedure should have finished after receiving MAC response"; -} \ No newline at end of file +} From 20be4a43f6adc5eddc9971c2fb48e28cddbbed50 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Thu, 29 Feb 2024 09:24:05 +0100 Subject: [PATCH 119/140] du,f1u: inject UE executor into F1-U bearer --- include/srsran/f1u/du/f1u_bearer_factory.h | 1 + include/srsran/f1u/du/f1u_gateway.h | 3 ++- .../f1u/local_connector/f1u_local_connector.h | 3 ++- lib/du_manager/du_ue/du_bearer.cpp | 3 ++- lib/f1u/du/f1u_bearer_factory.cpp | 13 +++++++++++-- lib/f1u/du/f1u_bearer_impl.cpp | 4 +++- lib/f1u/du/f1u_bearer_impl.h | 5 ++++- lib/f1u/local_connector/f1u_local_connector.cpp | 4 +++- tests/benchmarks/du_high/du_high_benchmark.cpp | 3 ++- tests/test_doubles/f1u/dummy_f1u_du_gateway.h | 5 +++-- .../unittests/du_manager/du_manager_test_helpers.h | 3 ++- tests/unittests/f1u/common/f1u_connector_test.cpp | 12 ++++++++---- tests/unittests/f1u/du/f1u_du_bearer_test.cpp | 3 ++- 13 files changed, 45 insertions(+), 17 deletions(-) diff --git a/include/srsran/f1u/du/f1u_bearer_factory.h b/include/srsran/f1u/du/f1u_bearer_factory.h index 3804fcf10f..695e344aa0 100644 --- a/include/srsran/f1u/du/f1u_bearer_factory.h +++ b/include/srsran/f1u/du/f1u_bearer_factory.h @@ -30,6 +30,7 @@ struct f1u_bearer_creation_message { f1u_rx_sdu_notifier* rx_sdu_notifier; f1u_tx_pdu_notifier* tx_pdu_notifier; timer_factory timers; + task_executor* ue_executor; }; /// \brief Creates an F1-U bearer for the DU. diff --git a/include/srsran/f1u/du/f1u_gateway.h b/include/srsran/f1u/du/f1u_gateway.h index 579d8b2427..36d39c0705 100644 --- a/include/srsran/f1u/du/f1u_gateway.h +++ b/include/srsran/f1u/du/f1u_gateway.h @@ -38,7 +38,8 @@ class f1u_du_gateway const up_transport_layer_info& dl_up_tnl_info, const up_transport_layer_info& ul_up_tnl_info, srs_du::f1u_rx_sdu_notifier& du_rx, - timer_factory timers) = 0; + timer_factory timers, + task_executor& ue_executor) = 0; virtual void remove_du_bearer(const up_transport_layer_info& dl_up_tnl_info) = 0; }; diff --git a/include/srsran/f1u/local_connector/f1u_local_connector.h b/include/srsran/f1u/local_connector/f1u_local_connector.h index fc7ff95261..306932d46e 100644 --- a/include/srsran/f1u/local_connector/f1u_local_connector.h +++ b/include/srsran/f1u/local_connector/f1u_local_connector.h @@ -80,7 +80,8 @@ class f1u_local_connector final : public srs_du::f1u_du_gateway, public f1u_cu_u const up_transport_layer_info& dl_up_tnl_info, const up_transport_layer_info& ul_up_tnl_info, srs_du::f1u_rx_sdu_notifier& du_rx, - timer_factory timers) override; + timer_factory timers, + task_executor& ue_executor) override; void remove_du_bearer(const up_transport_layer_info& dl_up_tnl_info) override; diff --git a/lib/du_manager/du_ue/du_bearer.cpp b/lib/du_manager/du_ue/du_bearer.cpp index 161d17f049..0d974e00e3 100644 --- a/lib/du_manager/du_ue/du_bearer.cpp +++ b/lib/du_manager/du_ue/du_bearer.cpp @@ -149,7 +149,8 @@ std::unique_ptr srsran::srs_du::create_drb(du_ue_index_t drb->dluptnl_info_list[0], drb->uluptnl_info_list[0], drb->connector.f1u_rx_sdu_notif, - timer_factory{du_params.services.timers, du_params.services.ue_execs.ctrl_executor(ue_index)}); + timer_factory{du_params.services.timers, du_params.services.ue_execs.ctrl_executor(ue_index)}, + du_params.services.ue_execs.f1u_dl_pdu_executor(ue_index)); if (f1u_drb == nullptr) { srslog::fetch_basic_logger("DU-MNG").warning("ue={}: Failed to connect F1-U bearer to CU-UP.", ue_index); return nullptr; diff --git a/lib/f1u/du/f1u_bearer_factory.cpp b/lib/f1u/du/f1u_bearer_factory.cpp index e50ac06f0e..54e4d7d1df 100644 --- a/lib/f1u/du/f1u_bearer_factory.cpp +++ b/lib/f1u/du/f1u_bearer_factory.cpp @@ -17,7 +17,16 @@ using namespace srs_du; std::unique_ptr srsran::srs_du::create_f1u_bearer(const f1u_bearer_creation_message& msg) { - auto bearer = std::make_unique( - msg.ue_index, msg.drb_id, msg.dl_tnl_info, msg.config, *msg.rx_sdu_notifier, *msg.tx_pdu_notifier, msg.timers); + srsran_assert(msg.rx_sdu_notifier != nullptr, "Cannot create F1-U bearer: RX SDU notifier is not configured."); + srsran_assert(msg.tx_pdu_notifier != nullptr, "Cannot create F1-U bearer: TX PDU notifier is not configured."); + srsran_assert(msg.ue_executor != nullptr, "Cannot create F1-U bearer: UE executor is not configured."); + auto bearer = std::make_unique(msg.ue_index, + msg.drb_id, + msg.dl_tnl_info, + msg.config, + *msg.rx_sdu_notifier, + *msg.tx_pdu_notifier, + msg.timers, + *msg.ue_executor); return bearer; } diff --git a/lib/f1u/du/f1u_bearer_impl.cpp b/lib/f1u/du/f1u_bearer_impl.cpp index dc0359393c..fecbf33fe1 100644 --- a/lib/f1u/du/f1u_bearer_impl.cpp +++ b/lib/f1u/du/f1u_bearer_impl.cpp @@ -20,11 +20,13 @@ f1u_bearer_impl::f1u_bearer_impl(uint32_t ue_index, const f1u_config& config, f1u_rx_sdu_notifier& rx_sdu_notifier_, f1u_tx_pdu_notifier& tx_pdu_notifier_, - timer_factory timers) : + timer_factory timers, + task_executor& ue_executor_) : logger("DU-F1-U", {ue_index, drb_id_, dl_tnl_info_}), cfg(config), rx_sdu_notifier(rx_sdu_notifier_), tx_pdu_notifier(tx_pdu_notifier_), + ue_executor(ue_executor_), ul_notif_timer(timers.create_timer()) { ul_notif_timer.set(std::chrono::milliseconds(cfg.t_notify), [this](timer_id_t tid) { on_expired_ul_notif_timer(); }); diff --git a/lib/f1u/du/f1u_bearer_impl.h b/lib/f1u/du/f1u_bearer_impl.h index 0173653bfc..f818d10fea 100644 --- a/lib/f1u/du/f1u_bearer_impl.h +++ b/lib/f1u/du/f1u_bearer_impl.h @@ -34,7 +34,8 @@ class f1u_bearer_impl final : public f1u_bearer, const f1u_config& config, f1u_rx_sdu_notifier& rx_sdu_notifier_, f1u_tx_pdu_notifier& tx_pdu_notifier_, - timer_factory timers); + timer_factory timers, + task_executor& ue_executor_); f1u_tx_sdu_handler& get_tx_sdu_handler() override { return *this; } f1u_tx_delivery_handler& get_tx_delivery_handler() override { return *this; } @@ -56,6 +57,8 @@ class f1u_bearer_impl final : public f1u_bearer, f1u_rx_sdu_notifier& rx_sdu_notifier; f1u_tx_pdu_notifier& tx_pdu_notifier; + task_executor& ue_executor; + /// Sentinel value representing a not-yet set PDCP SN static constexpr uint32_t unset_pdcp_sn = UINT32_MAX; diff --git a/lib/f1u/local_connector/f1u_local_connector.cpp b/lib/f1u/local_connector/f1u_local_connector.cpp index 4330cb9902..3c6b154381 100644 --- a/lib/f1u/local_connector/f1u_local_connector.cpp +++ b/lib/f1u/local_connector/f1u_local_connector.cpp @@ -115,7 +115,8 @@ srs_du::f1u_bearer* f1u_local_connector::create_du_bearer(uint32_t const up_transport_layer_info& dl_up_tnl_info, const up_transport_layer_info& ul_up_tnl_info, srs_du::f1u_rx_sdu_notifier& du_rx, - timer_factory timers) + timer_factory timers, + task_executor& ue_executor) { std::unique_lock lock(map_mutex); if (cu_map.find(ul_up_tnl_info) == cu_map.end()) { @@ -136,6 +137,7 @@ srs_du::f1u_bearer* f1u_local_connector::create_du_bearer(uint32_t f1u_msg.rx_sdu_notifier = &du_rx; f1u_msg.tx_pdu_notifier = du_tx.get(); f1u_msg.timers = timers; + f1u_msg.ue_executor = &ue_executor; std::unique_ptr f1u_bearer = srs_du::create_f1u_bearer(f1u_msg); srs_du::f1u_bearer* ptr = f1u_bearer.get(); diff --git a/tests/benchmarks/du_high/du_high_benchmark.cpp b/tests/benchmarks/du_high/du_high_benchmark.cpp index 7f84adc10c..07e254effd 100644 --- a/tests/benchmarks/du_high/du_high_benchmark.cpp +++ b/tests/benchmarks/du_high/du_high_benchmark.cpp @@ -297,7 +297,8 @@ class cu_up_simulator : public f1u_du_gateway const up_transport_layer_info& dl_tnl, const up_transport_layer_info& ul_tnl, srs_du::f1u_rx_sdu_notifier& du_rx, - timer_factory timers) override + timer_factory timers, + task_executor& ue_executor) override { du_notif_list.push_back(&du_rx); bearer_list.emplace_back(); diff --git a/tests/test_doubles/f1u/dummy_f1u_du_gateway.h b/tests/test_doubles/f1u/dummy_f1u_du_gateway.h index 151476364b..79c8d34a12 100644 --- a/tests/test_doubles/f1u/dummy_f1u_du_gateway.h +++ b/tests/test_doubles/f1u/dummy_f1u_du_gateway.h @@ -45,7 +45,8 @@ class cu_up_simulator : public f1u_du_gateway const up_transport_layer_info& dl_tnl, const up_transport_layer_info& ul_tnl, srs_du::f1u_rx_sdu_notifier& du_rx, - timer_factory timers) override + timer_factory timers, + task_executor& ue_executor) override { du_notif = &du_rx; return &bearer; @@ -55,4 +56,4 @@ class cu_up_simulator : public f1u_du_gateway }; } // namespace srs_du -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/tests/unittests/du_manager/du_manager_test_helpers.h b/tests/unittests/du_manager/du_manager_test_helpers.h index 143fc3d00d..fc030f886f 100644 --- a/tests/unittests/du_manager/du_manager_test_helpers.h +++ b/tests/unittests/du_manager/du_manager_test_helpers.h @@ -212,7 +212,8 @@ class f1u_gateway_dummy : public f1u_du_gateway const up_transport_layer_info& dl_tnl_info, const up_transport_layer_info& ul_tnl_info, srs_du::f1u_rx_sdu_notifier& du_rx, - timer_factory timers) override + timer_factory timers, + task_executor& ue_executor) override { if (next_bearer_is_created and f1u_bearers.count(dl_tnl_info) == 0) { f1u_bearers.insert(std::make_pair(dl_tnl_info, std::map{})); diff --git a/tests/unittests/f1u/common/f1u_connector_test.cpp b/tests/unittests/f1u/common/f1u_connector_test.cpp index cfefc24db2..cad562e97e 100644 --- a/tests/unittests/f1u/common/f1u_connector_test.cpp +++ b/tests/unittests/f1u/common/f1u_connector_test.cpp @@ -125,7 +125,8 @@ TEST_F(f1u_connector_test, attach_detach_cu_up_f1u_to_du_f1u) // Create DU TX notifier adapter and RX handler dummy_f1u_du_rx_sdu_notifier du_rx; - srs_du::f1u_bearer* du_bearer = du_gw->create_du_bearer(0, drb_id_t::drb1, config, dl_tnl, ul_tnl, du_rx, timers); + srs_du::f1u_bearer* du_bearer = + du_gw->create_du_bearer(0, drb_id_t::drb1, config, dl_tnl, ul_tnl, du_rx, timers, ue_worker); // Create CU RX handler and attach it to the DU TX cu_gw->attach_dl_teid(ul_tnl, dl_tnl); @@ -175,7 +176,8 @@ TEST_F(f1u_connector_test, detach_du_f1u_first) // Create DU TX notifier adapter and RX handler dummy_f1u_du_rx_sdu_notifier du_rx; - srs_du::f1u_bearer* du_bearer = du_gw->create_du_bearer(0, drb_id_t::drb1, config, dl_tnl, ul_tnl, du_rx, timers); + srs_du::f1u_bearer* du_bearer = + du_gw->create_du_bearer(0, drb_id_t::drb1, config, dl_tnl, ul_tnl, du_rx, timers, ue_worker); // Create CU RX handler and attach it to the DU TX cu_gw->attach_dl_teid(ul_tnl, dl_tnl); @@ -226,7 +228,8 @@ TEST_F(f1u_connector_test, update_du_f1u) // Create DU TX notifier adapter and RX handler dummy_f1u_du_rx_sdu_notifier du_rx1; - srs_du::f1u_bearer* du_bearer1 = du_gw->create_du_bearer(0, drb_id_t::drb1, config, dl_tnl1, ul_tnl, du_rx1, timers); + srs_du::f1u_bearer* du_bearer1 = + du_gw->create_du_bearer(0, drb_id_t::drb1, config, dl_tnl1, ul_tnl, du_rx1, timers, ue_worker); // Create CU RX handler and attach it to the DU TX cu_gw->attach_dl_teid(ul_tnl, dl_tnl1); @@ -254,7 +257,8 @@ TEST_F(f1u_connector_test, update_du_f1u) // Attach new DU bearer dummy_f1u_du_rx_sdu_notifier du_rx2; - srs_du::f1u_bearer* du_bearer2 = du_gw->create_du_bearer(0, drb_id_t::drb1, config, dl_tnl2, ul_tnl, du_rx2, timers); + srs_du::f1u_bearer* du_bearer2 = + du_gw->create_du_bearer(0, drb_id_t::drb1, config, dl_tnl2, ul_tnl, du_rx2, timers, ue_worker); // Attach new DL TEID cu_gw->attach_dl_teid(ul_tnl, dl_tnl2); diff --git a/tests/unittests/f1u/du/f1u_du_bearer_test.cpp b/tests/unittests/f1u/du/f1u_du_bearer_test.cpp index c96acc3257..5c29dcbe52 100644 --- a/tests/unittests/f1u/du/f1u_du_bearer_test.cpp +++ b/tests/unittests/f1u/du/f1u_du_bearer_test.cpp @@ -77,7 +77,8 @@ class f1u_du_test : public ::testing::Test, public f1u_trx_test config, *tester, *tester, - timer_factory{timers, ue_worker}); + timer_factory{timers, ue_worker}, + ue_worker); } void TearDown() override From a65e3d5222ad59c840dfb0ecd1c34d4fc0fdfe39 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Thu, 29 Feb 2024 09:42:49 +0100 Subject: [PATCH 120/140] du,f1u: handover PDU handling to associated UE executor --- lib/f1u/du/f1u_bearer_impl.cpp | 10 +++++++++- lib/f1u/du/f1u_bearer_impl.h | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/f1u/du/f1u_bearer_impl.cpp b/lib/f1u/du/f1u_bearer_impl.cpp index fecbf33fe1..61de975d12 100644 --- a/lib/f1u/du/f1u_bearer_impl.cpp +++ b/lib/f1u/du/f1u_bearer_impl.cpp @@ -50,11 +50,19 @@ void f1u_bearer_impl::handle_sdu(byte_buffer_chain sdu) } void f1u_bearer_impl::handle_pdu(nru_dl_message msg) +{ + auto fn = [this, m = std::move(msg)]() mutable { handle_pdu_impl(std::move(m)); }; + if (!ue_executor.execute(std::move(fn))) { + logger.log_warning("Dropped F1-U PDU, queue is full"); + } +} + +void f1u_bearer_impl::handle_pdu_impl(nru_dl_message msg) { logger.log_debug("F1-U bearer received PDU"); // handle T-PDU if (!msg.t_pdu.empty()) { - logger.log_debug("Delivering T-PDU of size={}, pdcp_sn={}", msg.t_pdu.length(), msg.pdcp_sn); + logger.log_debug("Delivering T-PDU. size={} pdcp_sn={}", msg.t_pdu.length(), msg.pdcp_sn); pdcp_tx_pdu tx_sdu = {}; tx_sdu.buf = std::move(msg.t_pdu); tx_sdu.pdcp_sn = msg.pdcp_sn; diff --git a/lib/f1u/du/f1u_bearer_impl.h b/lib/f1u/du/f1u_bearer_impl.h index f818d10fea..437aeff2d1 100644 --- a/lib/f1u/du/f1u_bearer_impl.h +++ b/lib/f1u/du/f1u_bearer_impl.h @@ -78,6 +78,8 @@ class f1u_bearer_impl final : public f1u_bearer, bool fill_highest_transmitted_pdcp_sn(nru_dl_data_delivery_status& status); bool fill_highest_delivered_pdcp_sn(nru_dl_data_delivery_status& status); void fill_data_delivery_status(nru_ul_message& msg); + + void handle_pdu_impl(nru_dl_message msg); }; } // namespace srs_du From 00870001f14fb6b50a06c3c37cd0e9255cc0fce2 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Wed, 6 Mar 2024 08:29:51 +0100 Subject: [PATCH 121/140] support: extend log message --- include/srsran/support/executors/strand_executor.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/srsran/support/executors/strand_executor.h b/include/srsran/support/executors/strand_executor.h index 100a9e97a2..a262d0da4d 100644 --- a/include/srsran/support/executors/strand_executor.h +++ b/include/srsran/support/executors/strand_executor.h @@ -235,7 +235,8 @@ class task_strand_with_queue : public base_task_strand } if (run_count != queue_size) { // Unexpected failure to pop enqueued tasks. It might be due to queue shutdown. - srslog::fetch_basic_logger("ALL").info("Couldn't run all pending tasks in strand"); + srslog::fetch_basic_logger("ALL").info( + "Couldn't run all pending tasks in strand. run_count={} queue_size={}", run_count, queue_size); } // We have run all the tasks that were enqueued since when we computed queue_size. @@ -442,4 +443,4 @@ std::vector> make_strand_executor_ptrs(OutExec&& return detail::make_strand_executors_iter_helper(std::forward(out_exec), strand_queues); } -} // namespace srsran \ No newline at end of file +} // namespace srsran From e9ea3fe386cb44286d197f79e7683d4f0d13296f Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Wed, 6 Mar 2024 17:31:28 +0100 Subject: [PATCH 122/140] gnb: use MPMC queue for ue_up_dl_exec --- apps/gnb/gnb_worker_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/gnb/gnb_worker_manager.cpp b/apps/gnb/gnb_worker_manager.cpp index 0e66b10ccf..eaaa4a4699 100644 --- a/apps/gnb/gnb_worker_manager.cpp +++ b/apps/gnb/gnb_worker_manager.cpp @@ -152,7 +152,7 @@ void worker_manager::create_du_cu_executors(const gnb_appconfig& appcfg) concurrent_queue_policy::lockfree_mpmc, appcfg.cu_up_cfg.gtpu_queue_size}, // TODO: Consider separate param for size of UL queue if needed. {fmt::format("ue_up_dl_exec#{}", i), - concurrent_queue_policy::lockfree_spsc, + concurrent_queue_policy::lockfree_mpmc, appcfg.cu_up_cfg.gtpu_queue_size}}}); } From d8e7b88f31d2862e312253eb629058f793cd88e1 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Wed, 6 Mar 2024 18:16:32 +0100 Subject: [PATCH 123/140] sched: avoid multiplexing of common and dedicated PUCCH grants --- lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp index 99ae1f313f..0b5b8716da 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp +++ b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp @@ -168,6 +168,11 @@ optional pucch_allocator_impl::alloc_ded_pucch_harq_ack_ue(cell_resour // Retrieve the existing PUCCH grants. const existing_pucch_grants existing_grants = get_existing_pucch_grants(pucchs, crnti, pucch_slot_alloc.slot); + // [Implementation-defined] Multiplexing of common and dedicated PUCCH grants are not yet supported. + if (existing_grants.format1_harq_common_grant != nullptr) { + return nullopt; + } + const unsigned harq_ack_bits_increment = 1; // Case 1) If there is a PUCCH format 2 grant, update it. From 257ceb691a82ed2538afd3f1a9a9842e7d921b15 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Wed, 6 Mar 2024 18:49:06 +0100 Subject: [PATCH 124/140] sched: avoid allocating PUSCH if PUCCH grant using common PUCCH resource exists --- lib/scheduler/pucch_scheduling/pucch_allocator.h | 6 ++++++ .../pucch_scheduling/pucch_allocator_impl.cpp | 4 ++-- lib/scheduler/pucch_scheduling/pucch_allocator_impl.h | 5 ++--- lib/scheduler/uci_scheduling/uci_allocator.h | 6 ++++++ lib/scheduler/uci_scheduling/uci_allocator_impl.cpp | 5 +++++ lib/scheduler/uci_scheduling/uci_allocator_impl.h | 2 ++ .../ue_scheduling/ue_cell_grid_allocator.cpp | 11 +++++++++++ .../scheduler/test_utils/dummy_test_components.h | 2 ++ 8 files changed, 36 insertions(+), 5 deletions(-) diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator.h b/lib/scheduler/pucch_scheduling/pucch_allocator.h index 08a7b716b7..e3b04d0f3b 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator.h +++ b/lib/scheduler/pucch_scheduling/pucch_allocator.h @@ -98,6 +98,12 @@ class pucch_allocator virtual pucch_uci_bits remove_ue_uci_from_pucch(cell_slot_resource_allocator& slot_alloc, rnti_t crnti, const ue_cell_configuration& ue_cell_cfg) = 0; + + /// Returns whether a PUCCH grant using common PUCCH resource already exists at a given slot for a UE. + /// \param[in] rnti RNTI of the UE. + /// \param[in] sl_tx Slot to search PUCCH grants. + /// \return Returns true if a PUCCH grant using common PUCCH resource exits. False, otherwise. + virtual bool has_common_pucch_f1_grant(rnti_t rnti, slot_point sl_tx) = 0; }; } // namespace srsran diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp index 0b5b8716da..c71324e9aa 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp +++ b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp @@ -848,7 +848,7 @@ void pucch_allocator_impl::remove_pucch_format1_from_grants(cell_slot_resource_a auto* it_harq = std::find_if(pucchs.begin(), pucchs.end(), [crnti, sl_tx, this](pucch_info& pucch) { return pucch.crnti == crnti and pucch.format == pucch_format::FORMAT_1 and pucch.format_1.sr_bits == sr_nof_bits::no_sr and pucch.format_1.harq_ack_nof_bits > 0 and - not is_pucch_f1_grant_common(crnti, sl_tx); + not has_common_pucch_f1_grant(crnti, sl_tx); }); if (it_harq != pucchs.end()) { @@ -1136,7 +1136,7 @@ pucch_allocator_impl::get_existing_pucch_grants(static_vector& pucchs, rnti_t rnti, slot_point sl_ack); diff --git a/lib/scheduler/uci_scheduling/uci_allocator.h b/lib/scheduler/uci_scheduling/uci_allocator.h index ce04159f4e..265cc508a0 100644 --- a/lib/scheduler/uci_scheduling/uci_allocator.h +++ b/lib/scheduler/uci_scheduling/uci_allocator.h @@ -81,6 +81,12 @@ class uci_allocator /// \param[in] crnti C-RNTI of the UE. /// \return Returns number of PDSCHs scheduled if UCI allocation if found, 0 otherwise. virtual uint8_t get_scheduled_pdsch_counter_in_ue_uci(cell_slot_resource_allocator& slot_alloc, rnti_t crnti) = 0; + + /// Returns whether an UCI HARQ-ACK allocated on common PUCCH resource exists at a given slot or not. + /// \param[in] crnti C-RNTI of the UE. + /// \param[in] sl_tx UCI slot. + /// \return Returns true if an UCI HARQ-ACK allocated on common PUCCH resource exists. False, otherwise. + virtual bool has_uci_harq_on_common_pucch_res(rnti_t crnti, slot_point sl_tx) = 0; }; } // namespace srsran diff --git a/lib/scheduler/uci_scheduling/uci_allocator_impl.cpp b/lib/scheduler/uci_scheduling/uci_allocator_impl.cpp index 44292f4104..f6c1df80cb 100644 --- a/lib/scheduler/uci_scheduling/uci_allocator_impl.cpp +++ b/lib/scheduler/uci_scheduling/uci_allocator_impl.cpp @@ -349,3 +349,8 @@ uint8_t uci_allocator_impl::get_scheduled_pdsch_counter_in_ue_uci(cell_slot_reso } return uci->scheduled_dl_pdcch_counter; } + +bool uci_allocator_impl::has_uci_harq_on_common_pucch_res(rnti_t rnti, slot_point sl_tx) +{ + return pucch_alloc.has_common_pucch_f1_grant(rnti, sl_tx); +} diff --git a/lib/scheduler/uci_scheduling/uci_allocator_impl.h b/lib/scheduler/uci_scheduling/uci_allocator_impl.h index d4ad81c050..2bc7c65c16 100644 --- a/lib/scheduler/uci_scheduling/uci_allocator_impl.h +++ b/lib/scheduler/uci_scheduling/uci_allocator_impl.h @@ -48,6 +48,8 @@ class uci_allocator_impl final : public uci_allocator uint8_t get_scheduled_pdsch_counter_in_ue_uci(cell_slot_resource_allocator& slot_alloc, rnti_t crnti) override; + bool has_uci_harq_on_common_pucch_res(rnti_t rnti, slot_point sl_tx) override; + private: // \brief Information cached by the UCI scheduler relative to the UCIs scheduled in the cell resource grid. Store // here any information that does not need to be stored in the PUCCH and PUSCH PDUs and does not need to be sent to diff --git a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp index a622c590c4..d4f83a8033 100644 --- a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp @@ -569,6 +569,17 @@ alloc_outcome ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& gr } } + // [Implementation-defined] We skip allocation of PUSCH if there is already a PUCCH grant scheduled using common PUCCH + // resources. + if (get_uci_alloc(grant.cell_index).has_uci_harq_on_common_pucch_res(u.crnti, pusch_alloc.slot)) { + logger.debug("ue={} rnti={} Allocation of PUSCH in slot={} skipped. Cause: UE has PUCCH grant using common PUCCH " + "resources scheduled", + u.ue_index, + u.crnti, + pusch_alloc.slot); + return alloc_outcome::skip_ue; + } + // When checking the number of remaining grants for PUSCH, take into account that the PUCCH grants for this UE will be // removed when multiplexing the UCI on PUSCH. if (pusch_alloc.result.ul.puschs.size() >= diff --git a/tests/unittests/scheduler/test_utils/dummy_test_components.h b/tests/unittests/scheduler/test_utils/dummy_test_components.h index 8445f1bc1e..bc7e9ff80f 100644 --- a/tests/unittests/scheduler/test_utils/dummy_test_components.h +++ b/tests/unittests/scheduler/test_utils/dummy_test_components.h @@ -132,6 +132,8 @@ class dummy_uci_allocator : public uci_allocator { return 0; } + + bool has_uci_harq_on_common_pucch_res(rnti_t crnti, slot_point sl_tx) override { return false; } }; class sched_cfg_dummy_notifier : public sched_configuration_notifier From 300b0bb471de106b3608af7e1e610941e00ac037 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Thu, 7 Mar 2024 11:16:31 +0100 Subject: [PATCH 125/140] sched: minor typo fixes --- lib/scheduler/uci_scheduling/uci_allocator.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/scheduler/uci_scheduling/uci_allocator.h b/lib/scheduler/uci_scheduling/uci_allocator.h index 265cc508a0..94367f554e 100644 --- a/lib/scheduler/uci_scheduling/uci_allocator.h +++ b/lib/scheduler/uci_scheduling/uci_allocator.h @@ -82,10 +82,10 @@ class uci_allocator /// \return Returns number of PDSCHs scheduled if UCI allocation if found, 0 otherwise. virtual uint8_t get_scheduled_pdsch_counter_in_ue_uci(cell_slot_resource_allocator& slot_alloc, rnti_t crnti) = 0; - /// Returns whether an UCI HARQ-ACK allocated on common PUCCH resource exists at a given slot or not. + /// Returns whether a UCI HARQ-ACK allocated on common PUCCH resource exists at a given slot or not. /// \param[in] crnti C-RNTI of the UE. /// \param[in] sl_tx UCI slot. - /// \return Returns true if an UCI HARQ-ACK allocated on common PUCCH resource exists. False, otherwise. + /// \return Returns true if a UCI HARQ-ACK allocated on common PUCCH resource exists. False, otherwise. virtual bool has_uci_harq_on_common_pucch_res(rnti_t crnti, slot_point sl_tx) = 0; }; From 16fa49fabd7aded2a037327e631bf3053247f486 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Thu, 7 Mar 2024 11:18:14 +0100 Subject: [PATCH 126/140] sched: mark function which determine whether a common PUCCH grant exists as const --- lib/scheduler/pucch_scheduling/pucch_allocator.h | 2 +- lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp | 7 ++++++- lib/scheduler/pucch_scheduling/pucch_allocator_impl.h | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator.h b/lib/scheduler/pucch_scheduling/pucch_allocator.h index e3b04d0f3b..5ea9b6a3a7 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator.h +++ b/lib/scheduler/pucch_scheduling/pucch_allocator.h @@ -103,7 +103,7 @@ class pucch_allocator /// \param[in] rnti RNTI of the UE. /// \param[in] sl_tx Slot to search PUCCH grants. /// \return Returns true if a PUCCH grant using common PUCCH resource exits. False, otherwise. - virtual bool has_common_pucch_f1_grant(rnti_t rnti, slot_point sl_tx) = 0; + virtual bool has_common_pucch_f1_grant(rnti_t rnti, slot_point sl_tx) const = 0; }; } // namespace srsran diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp index c71324e9aa..b5e186e5fd 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp +++ b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp @@ -170,6 +170,11 @@ optional pucch_allocator_impl::alloc_ded_pucch_harq_ack_ue(cell_resour // [Implementation-defined] Multiplexing of common and dedicated PUCCH grants are not yet supported. if (existing_grants.format1_harq_common_grant != nullptr) { + logger.debug( + "rnti={}: PUCCH HARQ-ACK for slot={} not allocated. Cause: Multiplexing of common and dedicated PUCCH grants " + "are not supported", + crnti, + pucch_slot_alloc.slot); return nullopt; } @@ -1136,7 +1141,7 @@ pucch_allocator_impl::get_existing_pucch_grants(static_vector Date: Fri, 8 Mar 2024 10:11:59 +0000 Subject: [PATCH 127/140] gtpu: lower GTP-U error log level to info This was done as the UE may continue to transmit during the de-registering procedure, at a time where the core already destroyed its PDU sessions. --- lib/gtpu/gtpu_echo_rx_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gtpu/gtpu_echo_rx_impl.h b/lib/gtpu/gtpu_echo_rx_impl.h index d0a6002dc7..16eabebb89 100644 --- a/lib/gtpu/gtpu_echo_rx_impl.h +++ b/lib/gtpu/gtpu_echo_rx_impl.h @@ -63,7 +63,7 @@ class gtpu_echo_rx : public gtpu_tunnel_base_rx return; case GTPU_MSG_ERROR_INDICATION: // TODO: unpack and print information elements; add handling - logger.log_error(pdu.buf.begin(), pdu.buf.end(), "Received error indication from peer"); + logger.log_info(pdu.buf.begin(), pdu.buf.end(), "Received error indication from peer"); // TS 29.281 Sec. 7.3.1: Error Indication // When a GTP-U node receives a G-PDU for which no EPS Bearer context, PDP context, PDU Session, MBMS Bearer // context, or RAB exists, the GTP-U node shall discard the G - PDU.If the TEID of the incoming G-PDU is From 04c52374d21ef9dc9f6f4e1cc7390dfd22dfdb67 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 6 Mar 2024 10:16:14 +0100 Subject: [PATCH 128/140] mac: remove error indication-dedicated executor and rely solely on scheduler event queue for thread safety --- apps/gnb/gnb_worker_manager.cpp | 10 +++------- .../srsran/du_high/du_high_executor_mapper.h | 3 --- lib/du_high/du_high_executor_strategies.h | 18 ++---------------- lib/mac/mac_dl/mac_cell_processor.cpp | 7 +------ lib/mac/mac_dl/mac_cell_processor.h | 2 -- lib/mac/mac_dl/mac_dl_processor.cpp | 1 - .../du_manager/du_manager_test_helpers.h | 1 - .../unittests/mac/mac_cell_processor_test.cpp | 1 - tests/unittests/mac/mac_ctrl_test_dummies.h | 1 - 9 files changed, 6 insertions(+), 38 deletions(-) diff --git a/apps/gnb/gnb_worker_manager.cpp b/apps/gnb/gnb_worker_manager.cpp index eaaa4a4699..796693ce80 100644 --- a/apps/gnb/gnb_worker_manager.cpp +++ b/apps/gnb/gnb_worker_manager.cpp @@ -166,14 +166,11 @@ void worker_manager::create_du_cu_executors(const gnb_appconfig& appcfg) const std::string cell_id_str = std::to_string(cell_id); const priority_multiqueue_worker du_cell_worker{ "du_cell#" + cell_id_str, - {{concurrent_queue_policy::lockfree_spsc, 4}, - {concurrent_queue_policy::lockfree_spsc, 8}, - {concurrent_queue_policy::lockfree_mpmc, task_worker_queue_size}}, + {{concurrent_queue_policy::lockfree_spsc, 4}, {concurrent_queue_policy::lockfree_mpmc, task_worker_queue_size}}, std::chrono::microseconds{10}, // Create Cell and slot indication executors. In case of ZMQ, we make the slot indication executor // synchronous. - {{"cell_exec#" + cell_id_str, task_priority::max - 2}, - {"err_ind#" + cell_id_str, task_priority ::max - 1}, + {{"cell_exec#" + cell_id_str, task_priority::max - 1}, {"slot_exec#" + cell_id_str, task_priority::max, {}, nullopt, is_blocking_mode_active}}, os_thread_realtime_priority::max() - 2, affinity_mng[cell_id].calcute_affinity_mask(gnb_sched_affinity_mask_types::l2_cell)}; @@ -235,8 +232,7 @@ void worker_manager::create_du_cu_executors(const gnb_appconfig& appcfg) // DU-high executor mapper. using exec_list = std::initializer_list; auto cell_exec_mapper = std::make_unique(exec_list{exec_map.at("cell_exec#" + cell_id_str)}, - exec_list{exec_map.at("slot_exec#" + cell_id_str)}, - exec_list{exec_map.at("err_ind#" + cell_id_str)}); + exec_list{exec_map.at("slot_exec#" + cell_id_str)}); auto ue_exec_mapper = std::make_unique(exec_list{exec_map.at("ue_up_ctrl_exec#0")}, exec_list{exec_map.at("ue_up_ul_exec#0")}, exec_list{exec_map.at("ue_up_dl_exec#0")}); diff --git a/include/srsran/du_high/du_high_executor_mapper.h b/include/srsran/du_high/du_high_executor_mapper.h index d8e51bf89b..5bb4efacdf 100644 --- a/include/srsran/du_high/du_high_executor_mapper.h +++ b/include/srsran/du_high/du_high_executor_mapper.h @@ -17,9 +17,6 @@ class du_high_cell_executor_mapper /// \brief Executor to handle slot_indication events for a given cell. virtual task_executor& slot_ind_executor(du_cell_index_t cell_index) = 0; - - /// \brief Executor to handle error_indication events for a given cell. - virtual task_executor& error_ind_executor(du_cell_index_t cell_index) = 0; }; /// This interface is used to allow the DU to choose between different UE-specific task executors. diff --git a/lib/du_high/du_high_executor_strategies.h b/lib/du_high/du_high_executor_strategies.h index b117c20da9..250d9da97e 100644 --- a/lib/du_high/du_high_executor_strategies.h +++ b/lib/du_high/du_high_executor_strategies.h @@ -155,19 +155,13 @@ class cell_executor_mapper final : public du_high_cell_executor_mapper /// \param cell_execs_ List of task executors that will be used by the MAC DL and scheduler. /// \param blocking_slot_ind sets whether slot indication tasks are processed synchronously or asynchronously explicit cell_executor_mapper(const std::initializer_list& cell_execs_, - const std::initializer_list& slot_execs_ = {}, - const std::initializer_list& err_ind_execs_ = {}) : - cell_execs(cell_execs_.begin(), cell_execs_.end()), - slot_execs(slot_execs_.begin(), slot_execs_.end()), - err_ind_execs(cell_execs_.begin(), cell_execs_.end()) + const std::initializer_list& slot_execs_ = {}) : + cell_execs(cell_execs_.begin(), cell_execs_.end()), slot_execs(slot_execs_.begin(), slot_execs_.end()) { srsran_assert(not cell_execs.empty(), "The number of DL executors must be higher than 1"); if (slot_execs.empty()) { slot_execs = cell_execs; } - if (err_ind_execs.empty()) { - err_ind_execs = cell_execs; - } } task_executor& executor(du_cell_index_t cell_index) override { return *cell_execs[cell_index % cell_execs.size()]; } @@ -177,11 +171,6 @@ class cell_executor_mapper final : public du_high_cell_executor_mapper return *slot_execs[cell_index % slot_execs.size()]; } - task_executor& error_ind_executor(du_cell_index_t cell_index) override - { - return *err_ind_execs[cell_index % err_ind_execs.size()]; - } - private: /// Executors used to process tasks related to the MAC DL and scheduler other than the slot indications. std::vector cell_execs; @@ -190,9 +179,6 @@ class cell_executor_mapper final : public du_high_cell_executor_mapper /// \c cell_execs or point to a sync_task_executor adapter stored in \c blocking_slot_execs, depending on whether /// slot indication tasks are processed synchronously or asynchronously. std::vector slot_execs; - - /// \brief Executors to handle error indications triggered from the FAPI. - std::vector err_ind_execs; }; /// \brief Task Executor Mapper for DU-high. diff --git a/lib/mac/mac_dl/mac_cell_processor.cpp b/lib/mac/mac_dl/mac_cell_processor.cpp index eadf995b19..689103fc6a 100644 --- a/lib/mac/mac_dl/mac_cell_processor.cpp +++ b/lib/mac/mac_dl/mac_cell_processor.cpp @@ -25,14 +25,12 @@ mac_cell_processor::mac_cell_processor(const mac_cell_creation_request& cell_cfg mac_cell_result_notifier& phy_notifier_, task_executor& cell_exec_, task_executor& slot_exec_, - task_executor& err_ind_exec_, task_executor& ctrl_exec_, mac_pcap& pcap_) : logger(srslog::fetch_basic_logger("MAC")), cell_cfg(cell_cfg_req_), cell_exec(cell_exec_), slot_exec(slot_exec_), - err_ind_exec(err_ind_exec_), ctrl_exec(ctrl_exec_), phy_cell(phy_notifier_), // The PDU pool has to be large enough to fit the maximum number of RARs and Paging PDUs per slot for all possible K0 @@ -76,10 +74,7 @@ void mac_cell_processor::handle_slot_indication(slot_point sl_tx) void mac_cell_processor::handle_error_indication(slot_point sl_tx, error_event event) { // Change execution context to slot indication executor. - if (not err_ind_exec.execute( - [this, sl_tx, event]() { sched.handle_error_indication(sl_tx, cell_cfg.cell_index, event); })) { - logger.warning("slot={}: Skipped error indication. Cause: DL task queue is full.", sl_tx); - } + sched.handle_error_indication(sl_tx, cell_cfg.cell_index, event); } void mac_cell_processor::handle_slot_indication_impl(slot_point sl_tx) diff --git a/lib/mac/mac_dl/mac_cell_processor.h b/lib/mac/mac_dl/mac_cell_processor.h index 26b63ac7b7..eb4f9ef1f7 100644 --- a/lib/mac/mac_dl/mac_cell_processor.h +++ b/lib/mac/mac_dl/mac_cell_processor.h @@ -34,7 +34,6 @@ class mac_cell_processor final : public mac_cell_slot_handler, public mac_cell_c mac_cell_result_notifier& phy_notifier, task_executor& cell_exec, task_executor& slot_exec, - task_executor& err_ind_exec, task_executor& ctrl_exec, mac_pcap& pcap); @@ -73,7 +72,6 @@ class mac_cell_processor final : public mac_cell_slot_handler, public mac_cell_c const mac_cell_creation_request cell_cfg; task_executor& cell_exec; task_executor& slot_exec; - task_executor& err_ind_exec; task_executor& ctrl_exec; mac_cell_result_notifier& phy_cell; diff --git a/lib/mac/mac_dl/mac_dl_processor.cpp b/lib/mac/mac_dl/mac_dl_processor.cpp index 64caeaf5fc..f0d73292d2 100644 --- a/lib/mac/mac_dl/mac_dl_processor.cpp +++ b/lib/mac/mac_dl/mac_dl_processor.cpp @@ -37,7 +37,6 @@ void mac_dl_processor::add_cell(const mac_cell_creation_request& cell_cfg_req) cfg.phy_notifier.get_cell(cell_cfg_req.cell_index), cfg.cell_exec_mapper.executor(cell_cfg_req.cell_index), cfg.cell_exec_mapper.slot_ind_executor(cell_cfg_req.cell_index), - cfg.cell_exec_mapper.error_ind_executor(cell_cfg_req.cell_index), cfg.ctrl_exec, cfg.pcap); } diff --git a/tests/unittests/du_manager/du_manager_test_helpers.h b/tests/unittests/du_manager/du_manager_test_helpers.h index fc030f886f..2e5a60e99c 100644 --- a/tests/unittests/du_manager/du_manager_test_helpers.h +++ b/tests/unittests/du_manager/du_manager_test_helpers.h @@ -58,7 +58,6 @@ class dummy_cell_executor_mapper : public du_high_cell_executor_mapper explicit dummy_cell_executor_mapper(task_executor& exec_) : exec(exec_) {} task_executor& executor(du_cell_index_t cell_index) override { return exec; } task_executor& slot_ind_executor(du_cell_index_t cell_index) override { return exec; } - task_executor& error_ind_executor(du_cell_index_t cell_index) override { return exec; } task_executor& exec; }; diff --git a/tests/unittests/mac/mac_cell_processor_test.cpp b/tests/unittests/mac/mac_cell_processor_test.cpp index 6350e5d9df..5d910cd549 100644 --- a/tests/unittests/mac/mac_cell_processor_test.cpp +++ b/tests/unittests/mac/mac_cell_processor_test.cpp @@ -33,7 +33,6 @@ class mac_cell_processor_tester : public ::testing::TestWithParam task_worker, task_worker, task_worker, - task_worker, pcap) { } diff --git a/tests/unittests/mac/mac_ctrl_test_dummies.h b/tests/unittests/mac/mac_ctrl_test_dummies.h index dfdc45801e..294b16aaeb 100644 --- a/tests/unittests/mac/mac_ctrl_test_dummies.h +++ b/tests/unittests/mac/mac_ctrl_test_dummies.h @@ -104,7 +104,6 @@ class dummy_dl_executor_mapper : public du_high_cell_executor_mapper task_executor& executor(du_cell_index_t cell_index) override { return *execs[cell_index % execs.size()]; } task_executor& slot_ind_executor(du_cell_index_t cell_index) override { return *execs[cell_index % execs.size()]; } - task_executor& error_ind_executor(du_cell_index_t cell_index) override { return *execs[cell_index % execs.size()]; } std::vector execs; }; From f9d3057a379dcf7521110c6828a3eafb08a6d61a Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 6 Mar 2024 16:39:27 +0100 Subject: [PATCH 129/140] mac: use HARQ buffer pool to speed up MAC DL UE creation --- lib/mac/CMakeLists.txt | 1 + lib/mac/mac_dl/cell_dl_harq_buffer_pool.cpp | 107 ++++++++++++++++++ lib/mac/mac_dl/cell_dl_harq_buffer_pool.h | 54 +++++++++ lib/mac/mac_dl/dl_sch_pdu_assembler.cpp | 30 +++-- lib/mac/mac_dl/dl_sch_pdu_assembler.h | 6 +- lib/mac/mac_dl/mac_cell_processor.cpp | 10 +- lib/mac/mac_dl/mac_cell_processor.h | 7 ++ lib/mac/mac_dl/mac_dl_processor.cpp | 19 +++- lib/mac/mac_dl/mac_dl_ue_manager.cpp | 16 +-- lib/mac/mac_dl/mac_dl_ue_manager.h | 19 +--- .../mac/dl_sch_pdu_assembler_test.cpp | 12 +- 11 files changed, 228 insertions(+), 53 deletions(-) create mode 100644 lib/mac/mac_dl/cell_dl_harq_buffer_pool.cpp create mode 100644 lib/mac/mac_dl/cell_dl_harq_buffer_pool.h diff --git a/lib/mac/CMakeLists.txt b/lib/mac/CMakeLists.txt index 404bbbf99a..6ac0a7dfde 100644 --- a/lib/mac/CMakeLists.txt +++ b/lib/mac/CMakeLists.txt @@ -22,6 +22,7 @@ set(SOURCES mac_factory.cpp mac_dl/paging_pdu_assembler.cpp mac_dl/ssb_assembler.cpp mac_dl/mac_dl_ue_manager.cpp + mac_dl/cell_dl_harq_buffer_pool.cpp mac_ul/mac_ul_sch_pdu.cpp mac_ul/ul_bsr.cpp mac_ul/pdu_rx_handler.cpp diff --git a/lib/mac/mac_dl/cell_dl_harq_buffer_pool.cpp b/lib/mac/mac_dl/cell_dl_harq_buffer_pool.cpp new file mode 100644 index 0000000000..4c7db022c7 --- /dev/null +++ b/lib/mac/mac_dl/cell_dl_harq_buffer_pool.cpp @@ -0,0 +1,107 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "cell_dl_harq_buffer_pool.h" +#include "srsran/ran/pdsch/pdsch_constants.h" + +using namespace srsran; + +/// Derive maximum TB/MAC PDU length given a cell parameters. +static units::bytes derive_max_pdu_length(unsigned cell_nof_prbs, unsigned nof_ports) +{ + srsran_assert(nof_ports >= 1 and nof_ports <= pdsch_constants::CODEWORD_MAX_NOF_LAYERS, "Invalid number of ports"); + units::bits cw_max_size{pdsch_constants::MAX_NRE_PER_RB * cell_nof_prbs * nof_ports * + pdsch_constants::MAX_MODULATION_ORDER}; + return cw_max_size.round_up_to_bytes(); +} + +// (Implementation-defined) Batch of DL HARQ buffers to allocate every time the pool is getting depleted. +const unsigned DL_HARQ_ALLOC_BATCH = MAX_NOF_HARQS * 2; + +// (Implementation-defined) Number of DL HARQ buffers to allocate in the control executor in each executor call. This +// value should be small to avoid blocking the control executor for too long. +const unsigned DL_HARQ_ALLOC_MINIBATCH = 2; + +cell_dl_harq_buffer_pool::cell_dl_harq_buffer_pool(unsigned cell_nof_prbs, + unsigned nof_ports, + task_executor& ctrl_exec_) : + max_pdu_len(derive_max_pdu_length(cell_nof_prbs, nof_ports).value()), + ctrl_exec(ctrl_exec_), + logger(srslog::fetch_basic_logger("MAC")), + cell_buffers(MAX_NOF_DU_UES) +{ + buffer_cache.reserve(MAX_NOF_DU_UES * MAX_NOF_HARQS); + + // Preallocate DL HARQ buffers for any UEs that may be added. + for (unsigned i = 0; i < DL_HARQ_ALLOC_BATCH; i++) { + buffer_cache.emplace_back(max_pdu_len); + } +} + +void cell_dl_harq_buffer_pool::allocate_ue_buffers(du_ue_index_t ue_index, unsigned nof_harqs) +{ + srsran_sanity_check(is_du_ue_index_valid(ue_index), "Invalid UE index"); + srsran_assert(nof_harqs <= MAX_NOF_HARQS, "Invalid maximum number of HARQs"); + + ue_dl_harq_buffer_list& ue_harqs = cell_buffers[ue_index]; + + if (not ue_harqs.empty()) { + logger.error("ue={}: HARQ buffers already allocated for new UE", ue_index); + } + + // Grow the list of HARQ buffers associated with this UE. + while (ue_harqs.size() < nof_harqs) { + if (buffer_cache.empty()) { + // Allocate a new HARQ buffer as there are not enough buffers in the cache. + // In general, we should avoid allocating a DL HARQ at this point, to avoid delaying the UE creation. + ue_harqs.emplace_back(max_pdu_len); + } else { + // Reuse a HARQ buffer from the cache. + ue_harqs.push_back(std::move(buffer_cache.back())); + buffer_cache.pop_back(); + } + } + + // Defer the growth of the DL HARQ buffer pool. + // We do not want to perform this operation at this point to avoid affecting the UE creation latency. + grow_pool(); +} + +void cell_dl_harq_buffer_pool::deallocate_ue_buffers(du_ue_index_t ue_idx) +{ + srsran_assert(is_du_ue_index_valid(ue_idx), "Invalid UE index"); + ue_dl_harq_buffer_list& ue_harqs = cell_buffers[ue_idx]; + + // Move allocated HARQs for this UE into the cache. + for (std::vector& harq : ue_harqs) { + buffer_cache.push_back(std::move(harq)); + } + ue_harqs.clear(); +} + +void cell_dl_harq_buffer_pool::grow_pool() +{ + if (buffer_cache.size() >= DL_HARQ_ALLOC_BATCH) { + // Stop growing the pool if it has enough DL HARQ buffers in cache. + return; + } + + if (not ctrl_exec.defer([this]() { + // Allocate minibatch of DL HARQ buffers and save them in cache. + for (unsigned i = 0; i != DL_HARQ_ALLOC_MINIBATCH; ++i) { + buffer_cache.emplace_back(max_pdu_len); + } + + // Dispatch new task to grow pool if it hasn't yet achieved the desired size. + grow_pool(); + })) { + logger.warning("Failed to dispatch task to allocate DL HARQ buffers"); + } +} diff --git a/lib/mac/mac_dl/cell_dl_harq_buffer_pool.h b/lib/mac/mac_dl/cell_dl_harq_buffer_pool.h new file mode 100644 index 0000000000..1da8e093ab --- /dev/null +++ b/lib/mac/mac_dl/cell_dl_harq_buffer_pool.h @@ -0,0 +1,54 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +#include "srsran/adt/span.h" +#include "srsran/ran/du_types.h" +#include "srsran/scheduler/harq_id.h" +#include "srsran/support/executors/task_executor.h" + +namespace srsran { + +/// Class that manages the allocation, deallocation and fetching of DL HARQ buffers for a given cell. +class cell_dl_harq_buffer_pool +{ + using ue_dl_harq_buffer_list = static_vector, MAX_NOF_HARQS>; + +public: + explicit cell_dl_harq_buffer_pool(unsigned cell_nof_prbs, unsigned nof_ports, task_executor& ctrl_exec); + + void allocate_ue_buffers(du_ue_index_t ue_index, unsigned nof_harqs); + + void deallocate_ue_buffers(du_ue_index_t ue_index); + + /// Get DL HARQ buffer for a given UE. + span dl_harq_buffer(du_ue_index_t ue_index, harq_id_t h_id) + { + srsran_sanity_check(is_du_ue_index_valid(ue_index), "Invalid UE index"); + srsran_assert(cell_buffers[ue_index].size() >= h_id, "Invalid HARQ ID={}", h_id); + return cell_buffers[ue_index][h_id]; + } + +private: + const unsigned max_pdu_len; + task_executor& ctrl_exec; + srslog::basic_logger& logger; + + void grow_pool(); + + // Pool of DL HARQ buffers for a given cell. + std::vector cell_buffers; + + // Buffers that can be reused for the creation of new UE HARQ buffers. + std::vector> buffer_cache; +}; + +} // namespace srsran \ No newline at end of file diff --git a/lib/mac/mac_dl/dl_sch_pdu_assembler.cpp b/lib/mac/mac_dl/dl_sch_pdu_assembler.cpp index ff15772ecc..0f71b2d96e 100644 --- a/lib/mac/mac_dl/dl_sch_pdu_assembler.cpp +++ b/lib/mac/mac_dl/dl_sch_pdu_assembler.cpp @@ -9,6 +9,7 @@ */ #include "dl_sch_pdu_assembler.h" +#include "cell_dl_harq_buffer_pool.h" #include "srsran/adt/byte_buffer_chain.h" #include "srsran/ran/pdsch/pdsch_constants.h" #include "srsran/support/error_handling.h" @@ -250,8 +251,8 @@ class dl_sch_pdu_assembler::pdu_log_builder // ///////////////////////// -dl_sch_pdu_assembler::dl_sch_pdu_assembler(mac_dl_ue_manager& ue_mng_) : - ue_mng(ue_mng_), logger(srslog::fetch_basic_logger("MAC")) +dl_sch_pdu_assembler::dl_sch_pdu_assembler(mac_dl_ue_manager& ue_mng_, cell_dl_harq_buffer_pool& cell_dl_harq_buffers) : + ue_mng(ue_mng_), harq_buffers(cell_dl_harq_buffers), logger(srslog::fetch_basic_logger("MAC")) { } @@ -264,17 +265,21 @@ span dl_sch_pdu_assembler::assemble_newtx_pdu(rnti_t const dl_msg_tb_info& tb_info, unsigned tb_size_bytes) { - span buffer = ue_mng.get_dl_harq_buffer(rnti, h_id, tb_idx); + du_ue_index_t ue_idx = ue_mng.get_ue_index(rnti); + if (ue_idx == INVALID_DU_UE_INDEX) { + logger.error("DL rnti={} h_id={}: Failed to assemble MAC PDU. Cause: C-RNTI has no associated UE id.", rnti, h_id); + return span(zero_buffer).first(tb_size_bytes); + } + + span buffer = harq_buffers.dl_harq_buffer(ue_idx, h_id); if (buffer.size() < tb_size_bytes) { - logger.error("DL ue={} rnti={} h_id={}: Failed to assemble MAC PDU. Cause: No HARQ buffers available", - ue_mng.get_ue_index(rnti), - rnti, - h_id); + logger.error( + "DL ue={} rnti={} h_id={}: Failed to assemble MAC PDU. Cause: No HARQ buffers available", ue_idx, rnti, h_id); return span(zero_buffer).first(tb_size_bytes); } dl_sch_pdu ue_pdu(buffer.first(tb_size_bytes)); - pdu_log_builder pdu_logger{ue_mng.get_ue_index(rnti), rnti, units::bytes{tb_size_bytes}, fmtbuf, logger}; + pdu_log_builder pdu_logger{ue_idx, rnti, units::bytes{tb_size_bytes}, fmtbuf, logger}; // Encode added subPDUs. for (const dl_msg_lc_info& sched_lch : tb_info.lc_chs_to_sched) { @@ -291,7 +296,7 @@ span dl_sch_pdu_assembler::assemble_newtx_pdu(rnti_t ue_pdu.add_padding(tb_size_bytes - current_size); } else if (current_size > tb_size_bytes) { logger.error("ERROR: Allocated subPDUs exceed TB size ({} > {})", current_size, tb_size_bytes); - return {}; + return span(zero_buffer).first(tb_size_bytes); } pdu_logger.log(); @@ -406,7 +411,12 @@ void dl_sch_pdu_assembler::assemble_ce(dl_sch_pdu& ue_pdu, span dl_sch_pdu_assembler::assemble_retx_pdu(rnti_t rnti, harq_id_t h_id, unsigned tb_idx, unsigned tbs_bytes) { - span buffer = ue_mng.get_dl_harq_buffer(rnti, h_id, tb_idx); + du_ue_index_t ue_idx = ue_mng.get_ue_index(rnti); + if (ue_idx == INVALID_DU_UE_INDEX) { + logger.error("DL rnti={} h_id={}: Failed to assemble MAC PDU. Cause: C-RNTI has no associated UE id.", rnti, h_id); + return span(zero_buffer).first(tbs_bytes); + } + span buffer = harq_buffers.dl_harq_buffer(ue_idx, h_id); if (buffer.size() < tbs_bytes) { logger.error("DL ue={} rnti={} h_id={}: Failed to assemble MAC PDU. Cause: No HARQ buffers available", ue_mng.get_ue_index(rnti), diff --git a/lib/mac/mac_dl/dl_sch_pdu_assembler.h b/lib/mac/mac_dl/dl_sch_pdu_assembler.h index 2c0eaf68e3..f4597e5d90 100644 --- a/lib/mac/mac_dl/dl_sch_pdu_assembler.h +++ b/lib/mac/mac_dl/dl_sch_pdu_assembler.h @@ -19,6 +19,7 @@ namespace srsran { class byte_buffer_chain; +class cell_dl_harq_buffer_pool; /// \brief This class represents and encodes a MAC DL-SCH PDU that may contain multiple subPDUs. /// Each subPDU is composed of a MAC subheader and MAC CE or MAC SDU payload. @@ -85,7 +86,7 @@ class dl_sch_pdu class dl_sch_pdu_assembler { public: - explicit dl_sch_pdu_assembler(mac_dl_ue_manager& ue_mng_); + explicit dl_sch_pdu_assembler(mac_dl_ue_manager& ue_mng_, cell_dl_harq_buffer_pool& cell_dl_harq_buffers); /// \brief Encodes a MAC DL-SCH PDU with the provided scheduler information. /// \param rnti RNTI for which the MAC PDU was allocated. @@ -118,7 +119,8 @@ class dl_sch_pdu_assembler /// Assemble MAC subPDU with a CE. void assemble_ce(dl_sch_pdu& ue_pdu, rnti_t rnti, const dl_msg_lc_info& subpdu, pdu_log_builder& pdu_logger); - mac_dl_ue_manager& ue_mng; + mac_dl_ue_manager& ue_mng; + cell_dl_harq_buffer_pool& harq_buffers; srslog::basic_logger& logger; // memory buffer to avoid allocations during formatting of pdus diff --git a/lib/mac/mac_dl/mac_cell_processor.cpp b/lib/mac/mac_dl/mac_cell_processor.cpp index 689103fc6a..f17fa1b898 100644 --- a/lib/mac/mac_dl/mac_cell_processor.cpp +++ b/lib/mac/mac_dl/mac_cell_processor.cpp @@ -33,6 +33,12 @@ mac_cell_processor::mac_cell_processor(const mac_cell_creation_request& cell_cfg slot_exec(slot_exec_), ctrl_exec(ctrl_exec_), phy_cell(phy_notifier_), + dl_harq_buffers(band_helper::get_n_rbs_from_bw( + MHz_to_bs_channel_bandwidth(cell_cfg.dl_carrier.carrier_bw_mhz), + cell_cfg.scs_common, + band_helper::get_freq_range(band_helper::get_band_from_dl_arfcn(cell_cfg.dl_carrier.arfcn))), + cell_cfg.dl_carrier.nof_ant, + ctrl_exec_), // The PDU pool has to be large enough to fit the maximum number of RARs and Paging PDUs per slot for all possible K0 // values. pdu_pool(MAX_DL_PDU_LENGTH, @@ -41,7 +47,7 @@ mac_cell_processor::mac_cell_processor(const mac_cell_creation_request& cell_cfg ssb_helper(cell_cfg_req_), sib_assembler(cell_cfg_req_.bcch_dl_sch_payloads), rar_assembler(pdu_pool), - dlsch_assembler(ue_mng_), + dlsch_assembler(ue_mng_, dl_harq_buffers), paging_assembler(pdu_pool), sched(sched_), ue_mng(ue_mng_), @@ -73,7 +79,7 @@ void mac_cell_processor::handle_slot_indication(slot_point sl_tx) void mac_cell_processor::handle_error_indication(slot_point sl_tx, error_event event) { - // Change execution context to slot indication executor. + // Forward error indication to the scheduler to be processed asynchronously. sched.handle_error_indication(sl_tx, cell_cfg.cell_index, event); } diff --git a/lib/mac/mac_dl/mac_cell_processor.h b/lib/mac/mac_dl/mac_cell_processor.h index eb4f9ef1f7..93abf53954 100644 --- a/lib/mac/mac_dl/mac_cell_processor.h +++ b/lib/mac/mac_dl/mac_cell_processor.h @@ -11,6 +11,7 @@ #pragma once #include "../mac_ctrl/mac_config.h" +#include "cell_dl_harq_buffer_pool.h" #include "dl_sch_pdu_assembler.h" #include "mac_dl_ue_manager.h" #include "mac_scheduler_cell_info_handler.h" @@ -46,6 +47,9 @@ class mac_cell_processor final : public mac_cell_slot_handler, public mac_cell_c void handle_slot_indication(slot_point sl_tx) override; void handle_error_indication(slot_point sl_tx, error_event event) override; + /// Gets DL HARQ buffer pool that is specific to this cell. + cell_dl_harq_buffer_pool& get_dl_harq_pool() { return dl_harq_buffers; } + private: void handle_slot_indication_impl(slot_point sl_tx); @@ -75,6 +79,9 @@ class mac_cell_processor final : public mac_cell_slot_handler, public mac_cell_c task_executor& ctrl_exec; mac_cell_result_notifier& phy_cell; + // Pool of DL HARQ buffers used for UE PDSCH. + cell_dl_harq_buffer_pool dl_harq_buffers; + ticking_ring_buffer_pool pdu_pool; /// ssb_helper: contains the SSB-specific parameters that are derived from those passed by the DU interface. These diff --git a/lib/mac/mac_dl/mac_dl_processor.cpp b/lib/mac/mac_dl/mac_dl_processor.cpp index f0d73292d2..c98c4b8d72 100644 --- a/lib/mac/mac_dl/mac_dl_processor.cpp +++ b/lib/mac/mac_dl/mac_dl_processor.cpp @@ -51,8 +51,12 @@ void mac_dl_processor::remove_cell(du_cell_index_t cell_index) async_task mac_dl_processor::add_ue(const mac_ue_create_request& request) { - // > Allocate UE DL HARQ buffers. - // Note: This is a large allocation, and therefore, should be done outside of the cell thread to avoid causing lates. + // > Allocate DL HARQ resources for the new UE. + // Note: This may call a large allocation, and therefore, should be done out of the cell thread to avoid causing + // lates. + cells[request.cell_index]->get_dl_harq_pool().allocate_ue_buffers(request.ue_index, MAX_NOF_HARQS); + + // > Create a MAC UE DL context. mac_dl_ue_context ue_inst(request); return launch_async([this, request, ue_inst = std::move(ue_inst)](coro_context>& ctx) mutable { @@ -73,18 +77,21 @@ async_task mac_dl_processor::add_ue(const mac_ue_create_request& request) async_task mac_dl_processor::remove_ue(const mac_ue_delete_request& request) { - return launch_async([this, request](coro_context>& ctx) { + return launch_async([this, request](coro_context>& ctx) mutable { CORO_BEGIN(ctx); - // 1. Change to respective DL executor + // Change to respective DL executor CORO_AWAIT(execute_on(cfg.cell_exec_mapper.executor(request.cell_index))); - // 2. Remove UE associated DL channels + // Remove UE associated DL channels ue_mng.remove_ue(request.ue_index); - // 3. Change back to CTRL executor before returning + // Change back to CTRL executor before returning CORO_AWAIT(execute_on(cfg.ctrl_exec)); + // Deallocate DL HARQ buffers back in the CTRL executor. + cells[request.cell_index]->get_dl_harq_pool().deallocate_ue_buffers(request.ue_index); + CORO_RETURN(); }); } diff --git a/lib/mac/mac_dl/mac_dl_ue_manager.cpp b/lib/mac/mac_dl/mac_dl_ue_manager.cpp index e34c164e6b..9e099ccd38 100644 --- a/lib/mac/mac_dl/mac_dl_ue_manager.cpp +++ b/lib/mac/mac_dl/mac_dl_ue_manager.cpp @@ -14,15 +14,8 @@ using namespace srsran; -mac_dl_ue_context::mac_dl_ue_context(const mac_ue_create_request& req) : - ue_index(req.ue_index), harq_buffers(MAX_NOF_HARQS) +mac_dl_ue_context::mac_dl_ue_context(const mac_ue_create_request& req) : ue_index(req.ue_index) { - // Resize each HARQ buffer to maximum DL PDU size. - // TODO: Account the maximum PDU length, given cell BW. - for (std::vector& harq : harq_buffers) { - harq.resize(MAX_DL_PDU_LENGTH); - } - // Store DL logical channel notifiers. addmod_logical_channels(req.bearers); @@ -74,12 +67,7 @@ bool mac_dl_ue_manager::remove_ue(du_ue_index_t ue_index) { // Erase UE from the repository. const std::lock_guard lock(ue_mutex[ue_index]); - if (not ue_db.contains(ue_index)) { - return false; - } - ue_db.erase(ue_index); - - return true; + return ue_db.erase(ue_index); } bool mac_dl_ue_manager::addmod_bearers(du_ue_index_t ue_index, diff --git a/lib/mac/mac_dl/mac_dl_ue_manager.h b/lib/mac/mac_dl/mac_dl_ue_manager.h index 6b021bed6c..c3af8ef01b 100644 --- a/lib/mac/mac_dl/mac_dl_ue_manager.h +++ b/lib/mac/mac_dl/mac_dl_ue_manager.h @@ -10,6 +10,7 @@ #pragma once +#include "cell_dl_harq_buffer_pool.h" #include "srsran/du_high/rnti_value_table.h" #include "srsran/mac/mac.h" #include "srsran/mac/mac_config.h" @@ -40,10 +41,6 @@ class mac_dl_ue_context du_ue_index_t get_ue_index() const { return ue_index; } - // HARQ buffer methods. - span dl_harq_buffer(harq_id_t h_id) { return harq_buffers[h_id]; } - span dl_harq_buffer(harq_id_t h_id) const { return harq_buffers[h_id]; } - // DL Logical Channel methods. const slotted_id_vector& logical_channels() const { return dl_bearers; } void addmod_logical_channels(span dl_logical_channels); @@ -53,7 +50,6 @@ class mac_dl_ue_context private: du_ue_index_t ue_index; - std::vector> harq_buffers; slotted_id_vector dl_bearers; ue_con_res_id_t msg3_subpdu = {}; }; @@ -122,19 +118,6 @@ class mac_dl_ue_manager /// \brief Returns UE Contention Resolution Id, which is derived from Msg3 bytes. ue_con_res_id_t get_con_res_id(rnti_t rnti); - span get_dl_harq_buffer(rnti_t rnti, harq_id_t h_id, unsigned tb_idx) - { - du_ue_index_t ue_index = rnti_table[rnti]; - if (ue_index == INVALID_DU_UE_INDEX) { - return {}; - } - std::lock_guard lock(ue_mutex[ue_index]); - if (not ue_db.contains(ue_index)) { - return {}; - } - return ue_db[ue_index].dl_harq_buffer(h_id); - } - private: du_rnti_table& rnti_table; diff --git a/tests/unittests/mac/dl_sch_pdu_assembler_test.cpp b/tests/unittests/mac/dl_sch_pdu_assembler_test.cpp index 9b7e9b06e1..cf347cf97c 100644 --- a/tests/unittests/mac/dl_sch_pdu_assembler_test.cpp +++ b/tests/unittests/mac/dl_sch_pdu_assembler_test.cpp @@ -8,11 +8,13 @@ * */ +#include "lib/mac/mac_dl/cell_dl_harq_buffer_pool.h" #include "lib/mac/mac_dl/dl_sch_pdu_assembler.h" #include "mac_test_helpers.h" #include "srsran/mac/config/mac_config_helpers.h" #include "srsran/ran/pdsch/pdsch_constants.h" #include "srsran/support/bit_encoding.h" +#include "srsran/support/executors/manual_task_worker.h" #include "srsran/support/test_utils.h" #include @@ -140,7 +142,11 @@ class dummy_dl_bearer : public mac_sdu_tx_builder class mac_dl_sch_assembler_tester : public testing::Test { public: - mac_dl_sch_assembler_tester() : ue_mng(rnti_table), dl_bearers(2), dl_sch_enc(ue_mng) + mac_dl_sch_assembler_tester() : + ue_mng(rnti_table), + dl_bearers(2), + harqs(MAX_NOF_PRBS, pdsch_constants::CODEWORD_MAX_NOF_LAYERS, task_worker), + dl_sch_enc(ue_mng, harqs) { srslog::fetch_basic_logger("MAC", true).set_level(srslog::basic_levels::debug); srslog::init(); @@ -159,6 +165,8 @@ class mac_dl_sch_assembler_tester : public testing::Test rnti_table.add_ue(req.crnti, req.ue_index); + harqs.allocate_ue_buffers(req.ue_index, MAX_NOF_HARQS); + mac_dl_ue_context u{req}; ue_mng.add_ue(std::move(u)); } @@ -171,6 +179,8 @@ class mac_dl_sch_assembler_tester : public testing::Test du_rnti_table rnti_table; mac_dl_ue_manager ue_mng; std::vector dl_bearers; + manual_task_worker task_worker{16}; + cell_dl_harq_buffer_pool harqs; dl_sch_pdu_assembler dl_sch_enc; }; From 4291a2887aed2ff64156f37aff5efb111aed05db Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Thu, 7 Mar 2024 14:52:25 +0100 Subject: [PATCH 130/140] mac: improve documentation of DL HARQ buffer pool --- lib/mac/mac_dl/cell_dl_harq_buffer_pool.cpp | 6 ++--- lib/mac/mac_dl/cell_dl_harq_buffer_pool.h | 26 ++++++++++++++++----- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/lib/mac/mac_dl/cell_dl_harq_buffer_pool.cpp b/lib/mac/mac_dl/cell_dl_harq_buffer_pool.cpp index 4c7db022c7..4dc61115be 100644 --- a/lib/mac/mac_dl/cell_dl_harq_buffer_pool.cpp +++ b/lib/mac/mac_dl/cell_dl_harq_buffer_pool.cpp @@ -71,7 +71,7 @@ void cell_dl_harq_buffer_pool::allocate_ue_buffers(du_ue_index_t ue_index, unsig // Defer the growth of the DL HARQ buffer pool. // We do not want to perform this operation at this point to avoid affecting the UE creation latency. - grow_pool(); + grow_pool_in_background(); } void cell_dl_harq_buffer_pool::deallocate_ue_buffers(du_ue_index_t ue_idx) @@ -86,7 +86,7 @@ void cell_dl_harq_buffer_pool::deallocate_ue_buffers(du_ue_index_t ue_idx) ue_harqs.clear(); } -void cell_dl_harq_buffer_pool::grow_pool() +void cell_dl_harq_buffer_pool::grow_pool_in_background() { if (buffer_cache.size() >= DL_HARQ_ALLOC_BATCH) { // Stop growing the pool if it has enough DL HARQ buffers in cache. @@ -100,7 +100,7 @@ void cell_dl_harq_buffer_pool::grow_pool() } // Dispatch new task to grow pool if it hasn't yet achieved the desired size. - grow_pool(); + grow_pool_in_background(); })) { logger.warning("Failed to dispatch task to allocate DL HARQ buffers"); } diff --git a/lib/mac/mac_dl/cell_dl_harq_buffer_pool.h b/lib/mac/mac_dl/cell_dl_harq_buffer_pool.h index 1da8e093ab..f16ee5fa8f 100644 --- a/lib/mac/mac_dl/cell_dl_harq_buffer_pool.h +++ b/lib/mac/mac_dl/cell_dl_harq_buffer_pool.h @@ -20,13 +20,23 @@ namespace srsran { /// Class that manages the allocation, deallocation and fetching of DL HARQ buffers for a given cell. class cell_dl_harq_buffer_pool { - using ue_dl_harq_buffer_list = static_vector, MAX_NOF_HARQS>; + /// Type representing a DL HARQ buffer. + using dl_harq_buffer_storage = std::vector; + + /// Type representing the list of DL HARQ buffers allocated for a given UE in a given cell. + using ue_dl_harq_buffer_list = static_vector; public: + /// \brief Construction of a DL HARQ buffer pool for a given cell. + /// \param cell_nof_prbs Number of PRBs of the cell. + /// \param nof_ports Number of ports of the cell. + /// \param ctrl_exec Executor to which DL HARQ buffer allocation tasks is dispatched. explicit cell_dl_harq_buffer_pool(unsigned cell_nof_prbs, unsigned nof_ports, task_executor& ctrl_exec); + /// \brief Allocate DL HARQ buffers for a newly created UE. void allocate_ue_buffers(du_ue_index_t ue_index, unsigned nof_harqs); + /// \brief Deallocate DL HARQ buffers for a removed UE. void deallocate_ue_buffers(du_ue_index_t ue_index); /// Get DL HARQ buffer for a given UE. @@ -38,17 +48,21 @@ class cell_dl_harq_buffer_pool } private: - const unsigned max_pdu_len; + // Maximum MAC PDU length, derived based on the cell properties. + const unsigned max_pdu_len; + // Executor to which DL HARQ buffer allocation tasks is dispatched in the background. task_executor& ctrl_exec; srslog::basic_logger& logger; - void grow_pool(); + // This function dispatches a task to grow the pool of DL HARQ buffers, using the \c ctrl_exec, in case the pool + // size decreased below a specific threshold. + void grow_pool_in_background(); - // Pool of DL HARQ buffers for a given cell. + // List of DL HARQ buffers currently allocated to UEs in the cell. std::vector cell_buffers; - // Buffers that can be reused for the creation of new UE HARQ buffers. + // DL HARQ buffers that are not associated with any UE and can be allocated to newly created UEs. std::vector> buffer_cache; }; -} // namespace srsran \ No newline at end of file +} // namespace srsran From a227089a3328819aad64164245f9f0577fed2fc6 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 7 Mar 2024 14:53:51 +0100 Subject: [PATCH 131/140] cu_cp: add meas manager ue context --- include/srsran/rrc/rrc_ue.h | 4 +- lib/cu_cp/adapters/rrc_ue_adapters.h | 5 +- .../cell_meas_manager_impl.cpp | 199 +++++++++--------- .../cell_meas_manager_impl.h | 78 +++++-- lib/cu_cp/cu_cp_impl.cpp | 6 +- lib/cu_cp/cu_cp_impl.h | 3 +- lib/cu_cp/cu_cp_impl_interface.h | 4 +- .../cu_cp_routine_manager.cpp | 3 +- .../routine_managers/cu_cp_routine_manager.h | 2 + lib/cu_cp/routines/ue_removal_routine.cpp | 4 + lib/cu_cp/routines/ue_removal_routine.h | 3 + lib/rrc/ue/rrc_ue_message_handlers.cpp | 7 +- .../cell_meas_manager_test.cpp | 28 ++- tests/unittests/rrc/test_helpers.h | 3 +- 14 files changed, 211 insertions(+), 138 deletions(-) diff --git a/include/srsran/rrc/rrc_ue.h b/include/srsran/rrc/rrc_ue.h index 04fb6b2870..7b96e57730 100644 --- a/include/srsran/rrc/rrc_ue.h +++ b/include/srsran/rrc/rrc_ue.h @@ -335,9 +335,11 @@ class rrc_ue_measurement_notifier virtual ~rrc_ue_measurement_notifier() = default; /// \brief Retrieve the measurement config (for any UE) connected to the given serving cell. + /// \param[in] ue_index The index of the UE to retrieve the measurement config for. /// \param[in] nci The cell id of the serving cell to update. /// \param[in] current_meas_config The current meas config of the UE (if applicable). - virtual optional on_measurement_config_request(nr_cell_id_t nci, + virtual optional on_measurement_config_request(ue_index_t ue_index, + nr_cell_id_t nci, optional current_meas_config = {}) = 0; /// \brief Submit measurement report for given UE to cell manager. diff --git a/lib/cu_cp/adapters/rrc_ue_adapters.h b/lib/cu_cp/adapters/rrc_ue_adapters.h index 9ff7dd8070..ac10e9ce7e 100644 --- a/lib/cu_cp/adapters/rrc_ue_adapters.h +++ b/lib/cu_cp/adapters/rrc_ue_adapters.h @@ -192,11 +192,12 @@ class rrc_ue_cu_cp_adapter : public rrc_ue_context_update_notifier, public rrc_u return ue_removal_handler->handle_ue_removal_request(ue_index); } - optional on_measurement_config_request(nr_cell_id_t nci, + optional on_measurement_config_request(ue_index_t ue_index, + nr_cell_id_t nci, optional current_meas_config = {}) override { srsran_assert(meas_handler != nullptr, "Measurement handler must not be nullptr"); - return meas_handler->handle_measurement_config_request(nci, current_meas_config); + return meas_handler->handle_measurement_config_request(ue_index, nci, current_meas_config); } void on_measurement_report(const ue_index_t ue_index, const rrc_meas_results& meas_results) override diff --git a/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.cpp b/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.cpp index 05059af99d..0635af006f 100644 --- a/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.cpp +++ b/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.cpp @@ -20,13 +20,10 @@ cell_meas_manager::cell_meas_manager(const cell_meas_manager_cfg& cfg_, { srsran_assert(is_valid_configuration(cfg), "Invalid cell measurement configuration"); log_cells(logger, cfg); - - // Mark zero index as occupied as the first valid meas(-obj) ID is 1. - meas_ids.emplace(0); - meas_obj_ids.emplace(0); } -optional cell_meas_manager::get_measurement_config(nr_cell_id_t serving_nci, +optional cell_meas_manager::get_measurement_config(ue_index_t ue_index, + nr_cell_id_t serving_nci, optional current_meas_config) { optional meas_cfg; @@ -40,10 +37,19 @@ optional cell_meas_manager::get_measurement_config(nr_cell_id_t // Measurement config is only generated if neighbor cells are configured or serving cell measurements are enabled. if (cell_config.ncells.empty() and !cell_config.periodic_report_cfg_id.has_value()) { - logger.debug("No neighbor cells configured and periodic serving cell reports disabled for nci={}", serving_nci); + logger.debug("ue={}: No neighbor cells configured and periodic serving cell reports disabled for nci={}", + ue_index, + serving_nci); return meas_cfg; } + // If no ue context for the current UE exists, create a new one. + if (ue_contexts.find(ue_index) == ue_contexts.end()) { + logger.debug("ue={}: Creating new measurement context", ue_index); + ue_contexts.emplace(ue_index, cell_meas_manager_ue_context{}); + } + auto& ue_context = ue_contexts.at(ue_index); + // Create fresh config. meas_cfg.emplace(); auto& new_cfg = meas_cfg.value(); @@ -54,15 +60,17 @@ optional cell_meas_manager::get_measurement_config(nr_cell_id_t // Remove measurement objects. for (const auto& meas_obj : old_cfg.meas_obj_to_add_mod_list) { - logger.debug("Removing meas_obj_id={}", meas_obj.meas_obj_id); - meas_obj_ids.erase(meas_obj_id_to_uint(meas_obj.meas_obj_id)); + logger.debug("ue={}: Removing meas_obj_id={}", ue_index, meas_obj.meas_obj_id); + ue_context.remove_meas_obj_id(meas_obj.meas_obj_id); + ue_context.meas_obj_id_to_nci.erase(meas_obj.meas_obj_id); new_cfg.meas_obj_to_rem_list.push_back(meas_obj.meas_obj_id); } // Remove measurement IDs. for (const auto& meas_id : old_cfg.meas_id_to_add_mod_list) { - logger.debug("Removing meas_id={}", meas_id.meas_id); - meas_ids.erase(meas_id_to_uint(meas_id.meas_id)); + logger.debug("ue={}: Removing meas_id={}", ue_index, meas_id.meas_id); + ue_context.remove_meas_id(meas_id.meas_id); + ue_context.meas_id_to_meas_context.erase(meas_id.meas_id); new_cfg.meas_id_to_rem_list.push_back(meas_id.meas_id); } @@ -72,12 +80,63 @@ optional cell_meas_manager::get_measurement_config(nr_cell_id_t } } + // Add periodic report configuration for the serving cell. + // Create meas object for serving cell if periodic report cfg is set + if (cell_config.periodic_report_cfg_id.has_value()) { + if (ue_context.meas_obj_ids.size() == MAX_NOF_MEAS_OBJ) { + logger.warning("ue={}: Can't add periodical report config for serving cell. Maximum ({}) reached", + ue_index, + MAX_NOF_MEAS_OBJ); + } else { + // add meas obj to add mod + rrc_meas_obj_to_add_mod meas_obj; + meas_obj.meas_obj_id = ue_context.allocate_meas_obj_id(); + auto& meas_obj_nr = meas_obj.meas_obj_nr.emplace(); + meas_obj_nr.ssb_freq = cell_config.serving_cell_cfg.ssb_arfcn; + meas_obj_nr.ssb_subcarrier_spacing = cell_config.serving_cell_cfg.ssb_scs; + meas_obj_nr.smtc1 = cell_config.serving_cell_cfg.ssb_mtc; + + // Mandatory fields. + meas_obj_nr.ref_sig_cfg.ssb_cfg_mob.emplace().derive_ssb_idx_from_cell = true; + meas_obj_nr.nrof_ss_blocks_to_average.emplace() = 8; + meas_obj_nr.quant_cfg_idx = 1; + meas_obj_nr.freq_band_ind_nr.emplace() = nr_band_to_uint(cell_config.serving_cell_cfg.band.value()); + + new_cfg.meas_obj_to_add_mod_list.push_back(meas_obj); + + // add meas obj id to lookup + ue_context.meas_obj_id_to_nci.emplace(meas_obj.meas_obj_id, serving_nci); + + // add report cfg to add mod + rrc_report_cfg_to_add_mod report_cfg_to_add_mod; + report_cfg_to_add_mod.report_cfg_id = cell_config.periodic_report_cfg_id.value(); + report_cfg_to_add_mod.report_cfg = cfg.report_config_ids.at(cell_config.periodic_report_cfg_id.value()); + + new_cfg.report_cfg_to_add_mod_list.push_back(report_cfg_to_add_mod); + + // Add meas id to link the neighbor cell and the report together. + rrc_meas_id_to_add_mod meas_id_to_add_mod; + + meas_id_to_add_mod.meas_id = ue_context.allocate_meas_id(); + meas_id_to_add_mod.meas_obj_id = meas_obj.meas_obj_id; + meas_id_to_add_mod.report_cfg_id = cell_config.periodic_report_cfg_id.value(); + + new_cfg.meas_id_to_add_mod_list.push_back(meas_id_to_add_mod); + + // add meas id to lookup + ue_context.meas_id_to_meas_context.emplace( + meas_id_to_add_mod.meas_id, meas_context_t{meas_id_to_add_mod.meas_obj_id, meas_id_to_add_mod.report_cfg_id}); + } + } + // Create meas object for each neighbor cell for (const auto& ncell : cell_config.ncells) { // Verify we have a complete config for this cell. if (!is_complete(cfg.cells.at(ncell.nci).serving_cell_cfg)) { - logger.debug( - "Cell {} is neighbor of {} but skipping due to missing measurement parameters", ncell.nci, serving_nci); + logger.debug("ue={}: Cell {} is neighbor of {} but skipping due to missing measurement parameters", + ue_index, + ncell.nci, + serving_nci); continue; } srsran_assert(cfg.cells.find(ncell.nci) != cfg.cells.end(), "Cell id {} not found in list", ncell.nci); @@ -85,7 +144,7 @@ optional cell_meas_manager::get_measurement_config(nr_cell_id_t // add meas obj to add mod rrc_meas_obj_to_add_mod meas_obj; - meas_obj.meas_obj_id = get_next_meas_obj_id(); + meas_obj.meas_obj_id = ue_context.allocate_meas_obj_id(); meas_obj.meas_obj_nr.emplace(); auto& meas_obj_nr = meas_obj.meas_obj_nr.value(); meas_obj_nr.ssb_freq = meas_cell_config.serving_cell_cfg.ssb_arfcn; @@ -101,7 +160,7 @@ optional cell_meas_manager::get_measurement_config(nr_cell_id_t new_cfg.meas_obj_to_add_mod_list.push_back(meas_obj); // add meas obj id to lookup - meas_obj_id_to_nci.emplace(meas_obj.meas_obj_id, ncell.nci); + ue_context.meas_obj_id_to_nci.emplace(meas_obj.meas_obj_id, ncell.nci); // add report cfg to add mod for (const auto& report_cfg_id : ncell.report_cfg_ids) { @@ -114,62 +173,15 @@ optional cell_meas_manager::get_measurement_config(nr_cell_id_t // Add meas id to link the neighbor cell and the report together. rrc_meas_id_to_add_mod meas_id_to_add_mod; - meas_id_to_add_mod.meas_id = get_next_meas_id(); + meas_id_to_add_mod.meas_id = ue_context.allocate_meas_id(); meas_id_to_add_mod.meas_obj_id = meas_obj.meas_obj_id; meas_id_to_add_mod.report_cfg_id = report_cfg_id; new_cfg.meas_id_to_add_mod_list.push_back(meas_id_to_add_mod); // add meas id to lookup - meas_id_to_meas_context.emplace(meas_id_to_add_mod.meas_id, - meas_context_t{meas_id_to_add_mod.meas_obj_id, meas_id_to_add_mod.report_cfg_id}); - } - } - - // Add periodic report configuration for the serving cell. - // Create meas object for serving cell if periodic report cfg is set - if (cell_config.periodic_report_cfg_id.has_value()) { - if (meas_obj_id_to_nci.size() == MAX_NOF_MEAS_OBJ) { - logger.warning("Can't add periodical report config for serving cell. Maximum ({}) reached", MAX_NOF_MEAS_OBJ); - } else { - // add meas obj to add mod - rrc_meas_obj_to_add_mod meas_obj; - meas_obj.meas_obj_id = get_next_meas_obj_id(); - auto& meas_obj_nr = meas_obj.meas_obj_nr.emplace(); - meas_obj_nr.ssb_freq = cell_config.serving_cell_cfg.ssb_arfcn; - meas_obj_nr.ssb_subcarrier_spacing = cell_config.serving_cell_cfg.ssb_scs; - meas_obj_nr.smtc1 = cell_config.serving_cell_cfg.ssb_mtc; - - // Mandatory fields. - meas_obj_nr.ref_sig_cfg.ssb_cfg_mob.emplace().derive_ssb_idx_from_cell = true; - meas_obj_nr.nrof_ss_blocks_to_average.emplace() = 8; - meas_obj_nr.quant_cfg_idx = 1; - meas_obj_nr.freq_band_ind_nr.emplace() = nr_band_to_uint(cell_config.serving_cell_cfg.band.value()); - - new_cfg.meas_obj_to_add_mod_list.push_back(meas_obj); - - // add meas obj id to lookup - meas_obj_id_to_nci.emplace(meas_obj.meas_obj_id, serving_nci); - - // add report cfg to add mod - rrc_report_cfg_to_add_mod report_cfg_to_add_mod; - report_cfg_to_add_mod.report_cfg_id = cell_config.periodic_report_cfg_id.value(); - report_cfg_to_add_mod.report_cfg = cfg.report_config_ids.at(cell_config.periodic_report_cfg_id.value()); - - new_cfg.report_cfg_to_add_mod_list.push_back(report_cfg_to_add_mod); - - // Add meas id to link the neighbor cell and the report together. - rrc_meas_id_to_add_mod meas_id_to_add_mod; - - meas_id_to_add_mod.meas_id = get_next_meas_id(); - meas_id_to_add_mod.meas_obj_id = meas_obj.meas_obj_id; - meas_id_to_add_mod.report_cfg_id = cell_config.periodic_report_cfg_id.value(); - - new_cfg.meas_id_to_add_mod_list.push_back(meas_id_to_add_mod); - - // add meas id to lookup - meas_id_to_meas_context.emplace(meas_id_to_add_mod.meas_id, - meas_context_t{meas_id_to_add_mod.meas_obj_id, meas_id_to_add_mod.report_cfg_id}); + ue_context.meas_id_to_meas_context.emplace( + meas_id_to_add_mod.meas_id, meas_context_t{meas_id_to_add_mod.meas_obj_id, meas_id_to_add_mod.report_cfg_id}); } } @@ -194,16 +206,16 @@ optional cell_meas_manager::get_cell_config(nr_cell_id_t nci) return cell_cfg; } -void cell_meas_manager::update_cell_config(nr_cell_id_t nci, - const serving_cell_meas_config& serv_cell_cfg_, - std::vector ncells_) +void cell_meas_manager::update_cell_config(nr_cell_id_t nci, + const serving_cell_meas_config& serv_cell_cfg_, + const std::vector& ncells_) { if (!is_complete(serv_cell_cfg_)) { logger.debug("Updating incomplete cell measurement configuration for nci={}", nci); } if (cfg.cells.find(nci) == cfg.cells.end()) { - logger.debug("No configuration to update for nci={}. Adding configuration.", nci); + logger.debug("No configuration to update for nci={}. Adding configuration", nci); cell_meas_config meas_cfg; meas_cfg.serving_cell_cfg = serv_cell_cfg_; @@ -211,7 +223,7 @@ void cell_meas_manager::update_cell_config(nr_cell_id_t cfg.cells.emplace(nci, meas_cfg); } else { - logger.debug("Updating measurement configuration for nci={}.", nci); + logger.debug("Updating measurement configuration for nci={}", nci); // Update serving cell config cfg.cells.at(nci).serving_cell_cfg = serv_cell_cfg_; @@ -236,13 +248,20 @@ optional get_ssb_rsrp(const rrc_meas_result_nr& meas_result) return rsrp; } -void cell_meas_manager::report_measurement(const ue_index_t ue_index, const rrc_meas_results& meas_results) +void cell_meas_manager::report_measurement(ue_index_t ue_index, const rrc_meas_results& meas_results) { logger.debug("ue={} Received measurement result with meas_id={}", ue_index, meas_results.meas_id); + // Verify measurement context exists for this UE. + if (ue_contexts.find(ue_index) == ue_contexts.end()) { + logger.debug("ue={}: No measurement context found", ue_index); + return; + } + auto& ue_context = ue_contexts.at(ue_index); + // Verify meas_id is valid. - if (meas_id_to_meas_context.find(meas_results.meas_id) == meas_id_to_meas_context.end()) { - logger.debug("ue={} Measurement result for unknown meas_id={} received.", ue_index, meas_results.meas_id); + if (ue_context.meas_id_to_meas_context.find(meas_results.meas_id) == ue_context.meas_id_to_meas_context.end()) { + logger.debug("ue={} Measurement result for unknown meas_id={} received", ue_index, meas_results.meas_id); return; } @@ -289,7 +308,8 @@ void cell_meas_manager::report_measurement(const ue_index_t ue_index, const rrc_ if (strongest_neighbor.has_value()) { // Report cell. - logger.info("Neighbor PCI={} (ssb_rsrp={}) stronger than current serving cell (ssb_rsrp={})", + logger.info("ue={}: Neighbor PCI={} (ssb_rsrp={}) stronger than current serving cell (ssb_rsrp={})", + ue_index, strongest_neighbor.value(), max_rsrp, serv_cell_rsrp.value()); @@ -300,34 +320,13 @@ void cell_meas_manager::report_measurement(const ue_index_t ue_index, const rrc_ } } -/// \brief Get the next available meas id. -meas_id_t cell_meas_manager::get_next_meas_id() +void cell_meas_manager::remove_ue_context(ue_index_t ue_index) { - // return invalid when no meas id is available - if (meas_id_to_meas_context.size() == MAX_NOF_MEAS) { - return meas_id_t::invalid; - } - - meas_id_t new_meas_id = (meas_id_t)meas_ids.find_first_empty(); - if (new_meas_id == meas_id_t::max) { - return meas_id_t::invalid; - } - meas_ids.emplace(meas_id_to_uint(new_meas_id)); - return new_meas_id; -} - -/// \brief Get the next available meas obj id. -meas_obj_id_t cell_meas_manager::get_next_meas_obj_id() -{ - // return invalid when no meas obj id is available - if (meas_obj_id_to_nci.size() == MAX_NOF_MEAS_OBJ) { - return meas_obj_id_t::invalid; + if (ue_contexts.find(ue_index) == ue_contexts.end()) { + logger.debug("ue={}: Can't remove UE measurement context. Cause: Context not found", ue_index); + return; } - meas_obj_id_t new_meas_obj_id = (meas_obj_id_t)meas_obj_ids.find_first_empty(); - if (new_meas_obj_id == meas_obj_id_t::max) { - return meas_obj_id_t::invalid; - } - meas_obj_ids.emplace(meas_obj_id_to_uint(new_meas_obj_id)); - return new_meas_obj_id; + logger.debug("ue={}: Measurement context removed", ue_index); + ue_contexts.erase(ue_index); } diff --git a/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h b/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h index 948820ca4f..3cbfa01873 100644 --- a/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h +++ b/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h @@ -27,35 +27,81 @@ class cell_meas_mobility_manager_notifier virtual void on_neighbor_better_than_spcell(ue_index_t ue_index, pci_t neighbor_pci) = 0; }; +class cell_meas_manager_ue_context +{ +public: + /// \brief Get the next available meas id. + meas_id_t allocate_meas_id() + { + // return invalid when no meas id is available + if (meas_ids.size() == MAX_NOF_MEAS) { + return meas_id_t::invalid; + } + + auto new_meas_id = (meas_id_t)meas_ids.find_first_empty(); + if (new_meas_id == meas_id_t::max) { + return meas_id_t::invalid; + } + meas_ids.emplace(meas_id_to_uint(new_meas_id)); + return new_meas_id; + } + + void remove_meas_id(meas_id_t meas_id) { meas_ids.erase(meas_id_to_uint(meas_id)); } + + /// \brief Get the next available meas obj id. + meas_obj_id_t allocate_meas_obj_id() + { + // return invalid when no meas obj id is available + if (meas_obj_ids.size() == MAX_NOF_MEAS_OBJ) { + return meas_obj_id_t::invalid; + } + + auto new_meas_obj_id = (meas_obj_id_t)meas_obj_ids.find_first_empty(); + if (new_meas_obj_id == meas_obj_id_t::max) { + return meas_obj_id_t::invalid; + } + meas_obj_ids.emplace(meas_obj_id_to_uint(new_meas_obj_id)); + return new_meas_obj_id; + } + + void remove_meas_obj_id(meas_obj_id_t meas_obj_id) { meas_obj_ids.erase(meas_obj_id_to_uint(meas_obj_id)); } + + slotted_array meas_ids; // 0 is reserved for invalid meas_id + slotted_array meas_obj_ids; // 0 is reserved for invalid meas_obj_id + + std::map meas_id_to_meas_context; + std::map meas_obj_id_to_nci; + + cell_meas_manager_ue_context() + { + // Mark zero index as occupied as the first valid meas(-obj) ID is 1. + meas_ids.emplace(0); + meas_obj_ids.emplace(0); + } +}; + /// Basic cell manager implementation class cell_meas_manager { public: - cell_meas_manager(const cell_meas_manager_cfg& cfg, cell_meas_mobility_manager_notifier& mobility_mng_notfier_); + cell_meas_manager(const cell_meas_manager_cfg& cfg_, cell_meas_mobility_manager_notifier& mobility_mng_notifier_); ~cell_meas_manager() = default; - optional get_measurement_config(nr_cell_id_t nci, optional current_meas_config = {}); + optional + get_measurement_config(ue_index_t ue_index, nr_cell_id_t nci, optional current_meas_config = {}); optional get_cell_config(nr_cell_id_t nci); - void update_cell_config(nr_cell_id_t nci, - const serving_cell_meas_config& serv_cell_cfg_, - std::vector ncells_ = {}); - void report_measurement(const ue_index_t ue_index, const rrc_meas_results& meas_results); + void update_cell_config(nr_cell_id_t nci, + const serving_cell_meas_config& serv_cell_cfg_, + const std::vector& ncells_ = {}); + void report_measurement(ue_index_t ue_index, const rrc_meas_results& meas_results); - /// \brief Get the next available meas_id. - meas_id_t get_next_meas_id(); - - /// \brief Get the next available meas_obj_id. - meas_obj_id_t get_next_meas_obj_id(); + void remove_ue_context(ue_index_t ue_index); private: cell_meas_manager_cfg cfg; cell_meas_mobility_manager_notifier& mobility_mng_notifier; - slotted_array meas_ids; - slotted_array meas_obj_ids; - - std::map meas_id_to_meas_context; - std::map meas_obj_id_to_nci; + std::map ue_contexts; srslog::basic_logger& logger; }; diff --git a/lib/cu_cp/cu_cp_impl.cpp b/lib/cu_cp/cu_cp_impl.cpp index 66d6b371ff..b2d5bfdf39 100644 --- a/lib/cu_cp/cu_cp_impl.cpp +++ b/lib/cu_cp/cu_cp_impl.cpp @@ -267,10 +267,11 @@ void cu_cp_impl::handle_handover_ue_context_push(ue_index_t source_ue_index, ue_ cu_up_db.get_cu_up(uint_to_cu_up_index(0)).update_ue_index(target_ue_index, source_ue_index); } -optional cu_cp_impl::handle_measurement_config_request(nr_cell_id_t nci, +optional cu_cp_impl::handle_measurement_config_request(ue_index_t ue_index, + nr_cell_id_t nci, optional current_meas_config) { - return cell_meas_mng.get_measurement_config(nci, current_meas_config); + return cell_meas_mng.get_measurement_config(ue_index, nci, current_meas_config); } void cu_cp_impl::handle_measurement_report(const ue_index_t ue_index, const rrc_meas_results& meas_results) @@ -295,6 +296,7 @@ void cu_cp_impl::handle_ue_removal_request(ue_index_t ue_index) e1_adapter != e1ap_adapters.end() ? &e1_adapter->second : nullptr, f1ap_adapters.at(du_index), ngap_adapter, + cell_meas_mng, ue_mng, logger); } diff --git a/lib/cu_cp/cu_cp_impl.h b/lib/cu_cp/cu_cp_impl.h index 5c8b10badd..0342498286 100644 --- a/lib/cu_cp/cu_cp_impl.h +++ b/lib/cu_cp/cu_cp_impl.h @@ -62,7 +62,8 @@ class cu_cp_impl final : public cu_cp, public cu_cp_impl_interface, public cu_cp void handle_handover_ue_context_push(ue_index_t source_ue_index, ue_index_t target_ue_index) override; // cu_cp_measurement_handler - optional handle_measurement_config_request(nr_cell_id_t nci, + optional handle_measurement_config_request(ue_index_t ue_index, + nr_cell_id_t nci, optional current_meas_config = {}) override; void handle_measurement_report(const ue_index_t ue_index, const rrc_meas_results& meas_results) override; diff --git a/lib/cu_cp/cu_cp_impl_interface.h b/lib/cu_cp/cu_cp_impl_interface.h index 14cc0ffc60..ec555a180e 100644 --- a/lib/cu_cp/cu_cp_impl_interface.h +++ b/lib/cu_cp/cu_cp_impl_interface.h @@ -226,9 +226,11 @@ class cu_cp_measurement_handler virtual ~cu_cp_measurement_handler() = default; /// \brief Handle a measurement config request (for any UE) connected to the given serving cell. + /// \param[in] ue_index The index of the UE to update the measurement config for. /// \param[in] nci The cell id of the serving cell to update. /// \param[in] current_meas_config The current meas config of the UE (if applicable). - virtual optional handle_measurement_config_request(nr_cell_id_t nci, + virtual optional handle_measurement_config_request(ue_index_t ue_index, + nr_cell_id_t nci, optional current_meas_config = {}) = 0; /// \brief Handle a measurement report for given UE. 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 7de30b96e6..f2100bb4ae 100644 --- a/lib/cu_cp/routine_managers/cu_cp_routine_manager.cpp +++ b/lib/cu_cp/routine_managers/cu_cp_routine_manager.cpp @@ -31,11 +31,12 @@ void cu_cp_routine_manager::start_ue_removal_routine(ue_index_t cu_cp_e1ap_ue_removal_notifier* e1ap_notifier, cu_cp_f1ap_ue_removal_notifier& f1ap_notifier, cu_cp_ngap_control_notifier& ngap_notifier, + cell_meas_manager& cell_meas_mng, ue_manager& ue_mng, srslog::basic_logger& logger) { ue_task_sched.handle_ue_async_task( ue_index, launch_async( - ue_index, rrc_du_notifier, e1ap_notifier, f1ap_notifier, ngap_notifier, ue_mng, logger)); + ue_index, rrc_du_notifier, e1ap_notifier, f1ap_notifier, ngap_notifier, cell_meas_mng, ue_mng, logger)); } diff --git a/lib/cu_cp/routine_managers/cu_cp_routine_manager.h b/lib/cu_cp/routine_managers/cu_cp_routine_manager.h index 2e0b947e12..0a9fc614fb 100644 --- a/lib/cu_cp/routine_managers/cu_cp_routine_manager.h +++ b/lib/cu_cp/routine_managers/cu_cp_routine_manager.h @@ -12,6 +12,7 @@ #include "../adapters/cu_cp_adapters.h" #include "../adapters/ngap_adapters.h" +#include "../cell_meas_manager/cell_meas_manager_impl.h" #include "../cu_cp_impl_interface.h" #include "../ue_manager/ue_manager_impl.h" #include "../ue_manager/ue_task_scheduler.h" @@ -40,6 +41,7 @@ class cu_cp_routine_manager cu_cp_e1ap_ue_removal_notifier* e1ap_notifier, cu_cp_f1ap_ue_removal_notifier& f1ap_notifier, cu_cp_ngap_control_notifier& ngap_notifier, + cell_meas_manager& cell_meas_mng, ue_manager& ue_mng, srslog::basic_logger& logger); diff --git a/lib/cu_cp/routines/ue_removal_routine.cpp b/lib/cu_cp/routines/ue_removal_routine.cpp index b190e7d509..237d3009a8 100644 --- a/lib/cu_cp/routines/ue_removal_routine.cpp +++ b/lib/cu_cp/routines/ue_removal_routine.cpp @@ -18,6 +18,7 @@ ue_removal_routine::ue_removal_routine(ue_index_t ue_index_ cu_cp_e1ap_ue_removal_notifier* e1ap_notifier_, cu_cp_f1ap_ue_removal_notifier& f1ap_notifier_, cu_cp_ngap_control_notifier& ngap_notifier_, + cell_meas_manager& cell_meas_mng_, ue_manager& ue_mng_, srslog::basic_logger& logger_) : ue_index(ue_index_), @@ -25,6 +26,7 @@ ue_removal_routine::ue_removal_routine(ue_index_t ue_index_ e1ap_notifier(e1ap_notifier_), f1ap_notifier(f1ap_notifier_), ngap_notifier(ngap_notifier_), + cell_meas_mng(cell_meas_mng_), ue_mng(ue_mng_), logger(logger_) { @@ -53,6 +55,8 @@ void ue_removal_routine::operator()(coro_context>& ctx) // Remove UE from UE manager ue_mng.remove_ue(ue_index); + cell_meas_mng.remove_ue_context(ue_index); + logger.info("ue={}: \"{}\" finalized", ue_index, name()); CORO_RETURN(); diff --git a/lib/cu_cp/routines/ue_removal_routine.h b/lib/cu_cp/routines/ue_removal_routine.h index 6ad78efab1..4d6f5779e7 100644 --- a/lib/cu_cp/routines/ue_removal_routine.h +++ b/lib/cu_cp/routines/ue_removal_routine.h @@ -12,6 +12,7 @@ #include "../adapters/cu_cp_adapters.h" #include "../adapters/ngap_adapters.h" +#include "../cell_meas_manager/cell_meas_manager_impl.h" #include "../cu_cp_impl_interface.h" #include "../ue_manager/ue_manager_impl.h" #include "../ue_manager/ue_task_scheduler.h" @@ -30,6 +31,7 @@ class ue_removal_routine cu_cp_e1ap_ue_removal_notifier* e1ap_notifier_, cu_cp_f1ap_ue_removal_notifier& f1ap_notifier_, cu_cp_ngap_control_notifier& ngap_notifier_, + cell_meas_manager& cell_meas_mng_, ue_manager& ue_mng_, srslog::basic_logger& logger_); @@ -43,6 +45,7 @@ class ue_removal_routine cu_cp_e1ap_ue_removal_notifier* e1ap_notifier; // to trigger removal of the UE at the E1AP cu_cp_f1ap_ue_removal_notifier& f1ap_notifier; // to trigger removal of the UE at the F1AP cu_cp_ngap_control_notifier& ngap_notifier; // to trigger removal of the UE at the NGAP + cell_meas_manager& cell_meas_mng; // to remove UE context from cell measurement manager ue_manager& ue_mng; // to remove UE context from DU processor srslog::basic_logger& logger; }; diff --git a/lib/rrc/ue/rrc_ue_message_handlers.cpp b/lib/rrc/ue/rrc_ue_message_handlers.cpp index 97e2476104..9d64f93d62 100644 --- a/lib/rrc/ue/rrc_ue_message_handlers.cpp +++ b/lib/rrc/ue/rrc_ue_message_handlers.cpp @@ -276,7 +276,7 @@ async_task rrc_ue_impl::handle_handover_reconfiguration_complete_expected( [this, timeout_ms, transaction_id, transaction = rrc_transaction{}](coro_context>& ctx) mutable { CORO_BEGIN(ctx); - logger.log_debug("Awaiting RRC Reconfiguration Complete"); + logger.log_debug("Awaiting RRC Reconfiguration Complete (timeout={}ms)", timeout_ms.count()); // create new transaction for RRC Reconfiguration procedure transaction = event_mng->transactions.create_transaction(transaction_id, timeout_ms); @@ -287,7 +287,7 @@ async_task rrc_ue_impl::handle_handover_reconfiguration_complete_expected( logger.log_debug("Received RRC Reconfiguration Complete after HO"); procedure_result = true; } else { - logger.log_debug("Did not receive RRC Reconfiguration Complete after HO (timeout)"); + logger.log_debug("Did not receive RRC Reconfiguration Complete after HO. Cause: timeout"); } CORO_RETURN(procedure_result); @@ -364,7 +364,8 @@ rrc_ue_release_context rrc_ue_impl::get_rrc_ue_release_context() optional rrc_ue_impl::generate_meas_config(optional current_meas_config) { // (Re-)generate measurement config and return result. - context.meas_cfg = measurement_notifier.on_measurement_config_request(context.cell.cgi.nci, current_meas_config); + context.meas_cfg = + measurement_notifier.on_measurement_config_request(context.ue_index, context.cell.cgi.nci, current_meas_config); return context.meas_cfg; } diff --git a/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test.cpp b/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test.cpp index 964b015c81..f944ebdb91 100644 --- a/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test.cpp +++ b/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test.cpp @@ -53,8 +53,9 @@ TEST_F(cell_meas_manager_test, when_empty_config_is_used_then_no_neighbor_cells_ { create_empty_manager(); + ue_index_t ue_index = ue_index_t::min; nr_cell_id_t cid = 0; - optional meas_cfg = manager->get_measurement_config(cid); + optional meas_cfg = manager->get_measurement_config(ue_index, cid); // Make sure meas_cfg is empty. verify_empty_meas_cfg(meas_cfg); @@ -64,8 +65,9 @@ TEST_F(cell_meas_manager_test, when_serving_cell_not_found_no_neighbor_cells_are { create_default_manager(); + ue_index_t ue_index = ue_index_t::min; nr_cell_id_t cid = 5; - optional meas_cfg = manager->get_measurement_config(cid); + optional meas_cfg = manager->get_measurement_config(ue_index, cid); // Make sure meas_cfg is empty. verify_empty_meas_cfg(meas_cfg); @@ -75,9 +77,11 @@ TEST_F(cell_meas_manager_test, when_serving_cell_found_then_neighbor_cells_are_a { create_default_manager(); + ue_index_t ue_index = ue_index_t::min; + meas_obj_id_t meas_obj_id = meas_obj_id_t::min; for (unsigned cid = 0; cid < 2; ++cid) { - optional meas_cfg = manager->get_measurement_config(cid); + optional meas_cfg = manager->get_measurement_config(ue_index, cid); check_default_meas_cfg(meas_cfg, meas_obj_id); meas_obj_id = uint_to_meas_obj_id(meas_obj_id_to_uint(meas_obj_id) + 2); } @@ -87,7 +91,8 @@ TEST_F(cell_meas_manager_test, when_inexisting_cell_config_is_updated_then_confi { create_default_manager(); - const nr_cell_id_t nci = 1; + ue_index_t ue_index = ue_index_t::min; + const nr_cell_id_t nci = 1; // get current config optional cell_cfg = manager->get_cell_config(nci); @@ -101,7 +106,7 @@ TEST_F(cell_meas_manager_test, when_inexisting_cell_config_is_updated_then_confi cell_cfg_val.serving_cell_cfg.ssb_scs.emplace() = subcarrier_spacing::kHz30; // Make sure meas_cfg is created. - optional meas_cfg = manager->get_measurement_config(nci); + optional meas_cfg = manager->get_measurement_config(ue_index, nci); check_default_meas_cfg(meas_cfg, meas_obj_id_t::min); } @@ -109,7 +114,8 @@ TEST_F(cell_meas_manager_test, when_incomplete_cell_config_is_updated_then_valid { create_default_manager(); - const nr_cell_id_t nci = 1; + ue_index_t ue_index = ue_index_t::min; + const nr_cell_id_t nci = 1; // get current config optional cell_cfg = manager->get_cell_config(nci); @@ -122,7 +128,7 @@ TEST_F(cell_meas_manager_test, when_incomplete_cell_config_is_updated_then_valid cell_cfg_val.serving_cell_cfg.ssb_scs.emplace() = subcarrier_spacing::kHz30; // Make sure meas_cfg is created. - optional meas_cfg = manager->get_measurement_config(nci); + optional meas_cfg = manager->get_measurement_config(ue_index, nci); check_default_meas_cfg(meas_cfg, meas_obj_id_t::min); } @@ -131,8 +137,9 @@ TEST_F(cell_meas_manager_test, when_empty_cell_config_is_used_then_meas_cfg_is_n // Create a manager without ncells and without report config. create_manager_without_ncells_and_periodic_report(); + ue_index_t ue_index = ue_index_t::min; nr_cell_id_t cid = 0; - optional meas_cfg = manager->get_measurement_config(cid); + optional meas_cfg = manager->get_measurement_config(ue_index, cid); // Make sure meas_cfg is empty. verify_empty_meas_cfg(meas_cfg); @@ -142,15 +149,16 @@ TEST_F(cell_meas_manager_test, when_old_meas_config_is_provided_old_ids_are_remo { create_default_manager(); + ue_index_t ue_index = ue_index_t::min; const nr_cell_id_t initial_nci = 0; // Make sure meas_cfg is created (no previous meas config provided) - optional initial_meas_cfg = manager->get_measurement_config(initial_nci); + optional initial_meas_cfg = manager->get_measurement_config(ue_index, initial_nci); check_default_meas_cfg(initial_meas_cfg, meas_obj_id_t::min); verify_meas_cfg(initial_meas_cfg); const nr_cell_id_t target_nci = 1; - optional target_meas_cfg = manager->get_measurement_config(target_nci, initial_meas_cfg); + optional target_meas_cfg = manager->get_measurement_config(ue_index, target_nci, initial_meas_cfg); // Make sure initial IDs are release again. ASSERT_EQ(target_meas_cfg.value().meas_obj_to_rem_list.at(0), diff --git a/tests/unittests/rrc/test_helpers.h b/tests/unittests/rrc/test_helpers.h index abdbbd2010..75a4ffaf9c 100644 --- a/tests/unittests/rrc/test_helpers.h +++ b/tests/unittests/rrc/test_helpers.h @@ -133,7 +133,8 @@ class dummy_rrc_ue_cu_cp_adapter : public rrc_ue_context_update_notifier, public void on_ue_removal_required(ue_index_t ue_index) override { logger.info("ue={}: Requested a UE removal", ue_index); } - optional on_measurement_config_request(nr_cell_id_t nci, + optional on_measurement_config_request(ue_index_t ue_index, + nr_cell_id_t nci, optional current_meas_config = {}) override { optional meas_cfg; From 2f87f35101cdef4a7586335f38741df5cfee5757 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 8 Mar 2024 18:54:51 +0100 Subject: [PATCH 132/140] fix maybe-initialized warning --- lib/support/executors/task_execution_manager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/support/executors/task_execution_manager.cpp b/lib/support/executors/task_execution_manager.cpp index 2433772a38..2c71c64b8c 100644 --- a/lib/support/executors/task_execution_manager.cpp +++ b/lib/support/executors/task_execution_manager.cpp @@ -319,7 +319,7 @@ struct worker_pool_context final : public common_task_execution_context qsizes; + std::array qsizes{}; for (unsigned i = 0; i != params.queues.size(); ++i) { qsizes[i] = params.queues[i].size; } @@ -472,7 +472,7 @@ struct priority_multiqueue_worker_context static std::unique_ptr create(const execution_config_helper::priority_multiqueue_worker& params) { - std::array qsizes; + std::array qsizes{}; for (unsigned i = 0; i != params.queues.size(); ++i) { qsizes[i] = params.queues[i].size; } From 44312a7795940712c22ab7a2a88c68b46e6985ba Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 8 Mar 2024 19:06:13 +0100 Subject: [PATCH 133/140] fix file headers --- include/srsran/du_high/du_high_executor_mapper.h | 9 +++++++++ tests/integrationtests/du_high/du_high_test.cpp | 1 - 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/srsran/du_high/du_high_executor_mapper.h b/include/srsran/du_high/du_high_executor_mapper.h index 5bb4efacdf..2d6c078623 100644 --- a/include/srsran/du_high/du_high_executor_mapper.h +++ b/include/srsran/du_high/du_high_executor_mapper.h @@ -1,3 +1,12 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ #pragma once diff --git a/tests/integrationtests/du_high/du_high_test.cpp b/tests/integrationtests/du_high/du_high_test.cpp index a4a0ba6479..df45559dc9 100644 --- a/tests/integrationtests/du_high/du_high_test.cpp +++ b/tests/integrationtests/du_high/du_high_test.cpp @@ -11,7 +11,6 @@ /// \file /// \brief Tests that check the setup/teardown, addition/removal of UEs in the DU-high class. -#include "lib/f1ap/common/f1ap_asn1_packer.h" #include "tests/integrationtests/du_high/test_utils/du_high_test_bench.h" #include "tests/test_doubles/f1ap/f1ap_test_message_validators.h" #include "tests/test_doubles/f1ap/f1ap_test_messages.h" From 2c4bdab85cd70eb12bf56aeab335a1ef3b6739ad Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 8 Mar 2024 19:17:50 +0100 Subject: [PATCH 134/140] fix maybe-initialized warning in execute_on --- include/srsran/support/async/execute_on.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/srsran/support/async/execute_on.h b/include/srsran/support/async/execute_on.h index 3d61c5082e..8e92c0561f 100644 --- a/include/srsran/support/async/execute_on.h +++ b/include/srsran/support/async/execute_on.h @@ -43,7 +43,7 @@ auto execute_on(TaskExecutor& exec) private: TaskExecutor& exec; - bool success; + bool success = false; }; return task_executor_awaiter{exec}; @@ -77,7 +77,7 @@ auto defer_to(TaskExecutor& exec) private: TaskExecutor& exec; - bool success; + bool success = false; }; return task_executor_awaiter{exec}; From f527eae19e58db30bc1778ee2e825a33831f4e5b Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Wed, 28 Feb 2024 13:30:52 +0100 Subject: [PATCH 135/140] rlc: refactor queue formatter... ...in preparation of rendering of log messages in backend. (Otherwise the queue would need to be copied to the backend) --- lib/rlc/rlc_sdu_queue_lockfree.h | 19 ++++++++++++++++--- lib/rlc/rlc_tx_am_entity.cpp | 12 ++++++++---- lib/rlc/rlc_tx_tm_entity.cpp | 6 +++--- lib/rlc/rlc_tx_um_entity.cpp | 6 +++--- 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/lib/rlc/rlc_sdu_queue_lockfree.h b/lib/rlc/rlc_sdu_queue_lockfree.h index 69682d1d75..e7056184af 100644 --- a/lib/rlc/rlc_sdu_queue_lockfree.h +++ b/lib/rlc/rlc_sdu_queue_lockfree.h @@ -199,6 +199,19 @@ class rlc_sdu_queue_lockfree /// \return The number of buffered SDU bytes that are not marked as discarded. uint32_t size_bytes() const { return n_bytes.load(std::memory_order_relaxed); } + /// \brief Container for return value of \c get_state function. + struct state { + uint32_t n_sdus; ///< Number of buffered SDUs that are not marked as discarded. + uint32_t n_bytes; ///< Number of buffered bytes that are not marked as discarded. + }; + + /// \brief Reads the state of the queue, i.e. number of buffered SDUs and bytes that are not marked as discarded. + /// + /// This function may be called by any thread. + /// + /// \return Current state of the queue. + state get_state() const { return {size_sdus(), size_bytes()}; } + /// \brief Checks if the internal queue is empty. /// /// This function may be called by any thread. @@ -281,7 +294,7 @@ class rlc_sdu_queue_lockfree namespace fmt { template <> -struct formatter { +struct formatter { template auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { @@ -289,10 +302,10 @@ struct formatter { } template - auto format(const srsran::rlc_sdu_queue_lockfree& q, FormatContext& ctx) + auto format(const srsran::rlc_sdu_queue_lockfree::state& state, FormatContext& ctx) -> decltype(std::declval().out()) { - return format_to(ctx.out(), "queued_sdus={} queued_bytes={}", q.size_sdus(), q.size_bytes()); + return format_to(ctx.out(), "queued_sdus={} queued_bytes={}", state.n_sdus, state.n_bytes); } }; diff --git a/lib/rlc/rlc_tx_am_entity.cpp b/lib/rlc/rlc_tx_am_entity.cpp index ded3b2dc4b..f16a6aed24 100644 --- a/lib/rlc/rlc_tx_am_entity.cpp +++ b/lib/rlc/rlc_tx_am_entity.cpp @@ -67,12 +67,16 @@ void rlc_tx_am_entity::handle_sdu(rlc_sdu sdu) sdu.time_of_arrival = std::chrono::high_resolution_clock::now(); size_t sdu_length = sdu.buf.length(); if (sdu_queue.write(sdu)) { - logger.log_info( - sdu.buf.begin(), sdu.buf.end(), "TX SDU. sdu_len={} pdcp_sn={} {}", sdu.buf.length(), sdu.pdcp_sn, sdu_queue); + logger.log_info(sdu.buf.begin(), + sdu.buf.end(), + "TX SDU. sdu_len={} pdcp_sn={} {}", + sdu.buf.length(), + sdu.pdcp_sn, + sdu_queue.get_state()); metrics.metrics_add_sdus(1, sdu_length); handle_changed_buffer_state(); } else { - logger.log_warning("Dropped SDU. sdu_len={} pdcp_sn={} {}", sdu_length, sdu.pdcp_sn, sdu_queue); + logger.log_warning("Dropped SDU. sdu_len={} pdcp_sn={} {}", sdu_length, sdu.pdcp_sn, sdu_queue.get_state()); metrics.metrics_add_lost_sdus(1); } } @@ -180,7 +184,7 @@ size_t rlc_tx_am_entity::build_new_pdu(span rlc_pdu_buf) // Read new SDU from TX queue rlc_sdu sdu; - logger.log_debug("Reading SDU from sdu_queue. {}", sdu_queue); + logger.log_debug("Reading SDU from sdu_queue. {}", sdu_queue.get_state()); if (not sdu_queue.read(sdu)) { logger.log_debug("SDU queue empty. grant_len={}", grant_len); return 0; diff --git a/lib/rlc/rlc_tx_tm_entity.cpp b/lib/rlc/rlc_tx_tm_entity.cpp index d63d1511c6..7de29897f9 100644 --- a/lib/rlc/rlc_tx_tm_entity.cpp +++ b/lib/rlc/rlc_tx_tm_entity.cpp @@ -37,11 +37,11 @@ void rlc_tx_tm_entity::handle_sdu(rlc_sdu sdu_) { size_t sdu_len = sdu_.buf.length(); if (sdu_queue.write(sdu_)) { - logger.log_info(sdu_.buf.begin(), sdu_.buf.end(), "TX SDU. sdu_len={} {}", sdu_len, sdu_queue); + logger.log_info(sdu_.buf.begin(), sdu_.buf.end(), "TX SDU. sdu_len={} {}", sdu_len, sdu_queue.get_state()); metrics.metrics_add_sdus(1, sdu_len); handle_changed_buffer_state(); } else { - logger.log_info("Dropped SDU. sdu_len={} {}", sdu_len, sdu_queue); + logger.log_info("Dropped SDU. sdu_len={} {}", sdu_len, sdu_queue.get_state()); metrics.metrics_add_lost_sdus(1); } } @@ -61,7 +61,7 @@ size_t rlc_tx_tm_entity::pull_pdu(span mac_sdu_buf) // Get a new SDU, if none is currently being transmitted if (sdu.buf.empty()) { - logger.log_debug("Reading SDU from sdu_queue. {}", sdu_queue); + logger.log_debug("Reading SDU from sdu_queue. {}", sdu_queue.get_state()); if (not sdu_queue.read(sdu)) { logger.log_debug("SDU queue empty. grant_len={}", grant_len); return 0; diff --git a/lib/rlc/rlc_tx_um_entity.cpp b/lib/rlc/rlc_tx_um_entity.cpp index f437815baa..3bf7ffc3db 100644 --- a/lib/rlc/rlc_tx_um_entity.cpp +++ b/lib/rlc/rlc_tx_um_entity.cpp @@ -50,11 +50,11 @@ void rlc_tx_um_entity::handle_sdu(rlc_sdu sdu_) "TX SDU. sdu_len={} pdcp_sn={} {}", sdu_.buf.length(), sdu_.pdcp_sn, - sdu_queue); + sdu_queue.get_state()); metrics.metrics_add_sdus(1, sdu_length); handle_changed_buffer_state(); } else { - logger.log_info("Dropped SDU. sdu_len={} pdcp_sn={} {}", sdu_length, sdu_.pdcp_sn, sdu_queue); + logger.log_info("Dropped SDU. sdu_len={} pdcp_sn={} {}", sdu_length, sdu_.pdcp_sn, sdu_queue.get_state()); metrics.metrics_add_lost_sdus(1); } } @@ -92,7 +92,7 @@ size_t rlc_tx_um_entity::pull_pdu(span mac_sdu_buf) // Get a new SDU, if none is currently being transmitted if (sdu.buf.empty()) { srsran_sanity_check(next_so == 0, "New TX SDU, but next_so={} > 0.", next_so); - logger.log_debug("Reading SDU from sdu_queue. {}", sdu_queue); + logger.log_debug("Reading SDU from sdu_queue. {}", sdu_queue.get_state()); if (not sdu_queue.read(sdu)) { logger.log_debug("SDU queue empty. grant_len={}", grant_len); return {}; From 6decc4c9d608b837c20f025d39d8e6e94838f031 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Wed, 28 Feb 2024 09:24:39 +0100 Subject: [PATCH 136/140] srslog: move prefix rendering to backend Introduce an optional "log_label" metadata that allows for passing custom labels (prefixes) that shall be prepended to each log message upon rendering in the backend. --- .../srsran/srslog/detail/log_entry_metadata.h | 1 + include/srsran/srslog/log_channel.h | 118 ++++++++++++++++++ include/srsran/support/prefixed_logger.h | 28 ++--- lib/srslog/formatters/text_formatter.cpp | 3 + 4 files changed, 135 insertions(+), 15 deletions(-) diff --git a/include/srsran/srslog/detail/log_entry_metadata.h b/include/srsran/srslog/detail/log_entry_metadata.h index b780ec84a0..544efce6e3 100644 --- a/include/srsran/srslog/detail/log_entry_metadata.h +++ b/include/srsran/srslog/detail/log_entry_metadata.h @@ -34,6 +34,7 @@ struct log_entry_metadata { fmt::dynamic_format_arg_store* store; std::string log_name; char log_tag; + std::string log_label; std::vector hex_dump; }; diff --git a/include/srsran/srslog/log_channel.h b/include/srsran/srslog/log_channel.h index 9291f1247e..5e90ff720f 100644 --- a/include/srsran/srslog/log_channel.h +++ b/include/srsran/srslog/log_channel.h @@ -44,6 +44,13 @@ struct log_channel_config { bool should_print_context = false; }; +/// Strong type to wrap a constant log label that is prepended to each log message. +struct log_label_t { + /// Optional log label. If set, will get printed in front of each log message. + /// Disabled by default. + std::string log_label; +}; + /// A log channel is the entity used for logging messages. /// /// It can deliver a log entry to one or more different sinks, for example a @@ -136,6 +143,38 @@ class log_channel backend.push(std::move(entry)); } + /// Builds the provided log entry and passes it to the backend. When the + /// channel is disabled the log entry will be discarded. + template + void operator()(const log_label_t& label, const char* fmtstr, Args&&... args) + { + if (!enabled()) { + return; + } + + // Populate the store with all incoming arguments. + auto* store = backend.alloc_arg_store(); + if (!store) { + return; + } + (void)std::initializer_list{(push_back(store, std::forward(args)), 0)...}; + + // Send the log entry to the backend. + log_formatter& formatter = log_sink.get_formatter(); + detail::log_entry entry = {&log_sink, + [&formatter](detail::log_entry_metadata&& metadata, fmt::memory_buffer& buffer) { + formatter.format(std::move(metadata), buffer); + }, + {std::chrono::high_resolution_clock::now(), + {ctx_value64, should_print_context}, + fmtstr, + store, + log_name, + log_tag, + label.log_label}}; + backend.push(std::move(entry)); + } + /// Builds the provided log entry and passes it to the backend. When the /// channel is disabled the log entry will be discarded. template @@ -200,6 +239,45 @@ class log_channel store, log_name, log_tag, + {}, + std::vector(buffer, buffer + len)}}; + backend.push(std::move(entry)); + } + + /// Builds the provided log entry and passes it to the backend. When the + /// channel is disabled the log entry will be discarded. + template + void operator()(const log_label_t& label, const uint8_t* buffer, size_t len, const char* fmtstr, Args&&... args) + { + if (!enabled()) { + return; + } + + // Populate the store with all incoming arguments. + auto* store = backend.alloc_arg_store(); + if (!store) { + return; + } + (void)std::initializer_list{(push_back(store, std::forward(args)), 0)...}; + + // Calculate the length to capture in the buffer. + if (hex_max_size >= 0) { + len = std::min(len, hex_max_size); + } + + // Send the log entry to the backend. + log_formatter& formatter = log_sink.get_formatter(); + detail::log_entry entry = {&log_sink, + [&formatter](detail::log_entry_metadata&& metadata, fmt::memory_buffer& buffer_) { + formatter.format(std::move(metadata), buffer_); + }, + {std::chrono::high_resolution_clock::now(), + {ctx_value64, should_print_context}, + fmtstr, + store, + log_name, + log_tag, + label.log_label, std::vector(buffer, buffer + len)}}; backend.push(std::move(entry)); } @@ -237,6 +315,7 @@ class log_channel store, log_name, log_tag, + {}, std::vector(buffer, buffer + len)}}; backend.push(std::move(entry)); } @@ -274,6 +353,45 @@ class log_channel store, log_name, log_tag, + {}, + std::vector(it_begin, it_end)}}; + backend.push(std::move(entry)); + } + + /// Builds the provided log entry and passes it to the backend. When the + /// channel is disabled the log entry will be discarded. + template ::value, int>::type = 0> + void operator()(const log_label_t& label, It it_begin, It it_end, const char* fmtstr, Args&&... args) + { + if (!enabled()) { + return; + } + + // Populate the store with all incoming arguments. + auto* store = backend.alloc_arg_store(); + if (!store) { + return; + } + (void)std::initializer_list{(push_back(store, std::forward(args)), 0)...}; + + // Calculate the length to capture in the buffer. + if (hex_max_size >= 0 && hex_max_size < std::distance(it_begin, it_end)) { + it_end = it_begin + hex_max_size; + } + + // Send the log entry to the backend. + log_formatter& formatter = log_sink.get_formatter(); + detail::log_entry entry = {&log_sink, + [&formatter](detail::log_entry_metadata&& metadata, fmt::memory_buffer& buffer) { + formatter.format(std::move(metadata), buffer); + }, + {std::chrono::high_resolution_clock::now(), + {ctx_value64, should_print_context}, + fmtstr, + store, + log_name, + log_tag, + label.log_label, std::vector(it_begin, it_end)}}; backend.push(std::move(entry)); } diff --git a/include/srsran/support/prefixed_logger.h b/include/srsran/support/prefixed_logger.h index b9fc4abef8..180781a064 100644 --- a/include/srsran/support/prefixed_logger.h +++ b/include/srsran/support/prefixed_logger.h @@ -25,13 +25,18 @@ template class prefixed_logger { public: - prefixed_logger(const std::string& log_name, Prefix prefix_, const char* prefix_separator_ = "") : - logger(srslog::fetch_basic_logger(log_name, false)), prefix(prefix_), prefix_separator(prefix_separator_) + prefixed_logger(const std::string& log_name, Prefix prefix, const char* prefix_separator = "") : + logger(srslog::fetch_basic_logger(log_name, false)) { + set_prefix(prefix, prefix_separator); } - void set_prefix(Prefix prefix_) { prefix = prefix_; } - Prefix get_prefix() const { return prefix; } + void set_prefix(Prefix prefix, const char* prefix_separator = "") + { + fmt::memory_buffer buffer; + fmt::format_to(buffer, "{}{}", prefix, prefix_separator); + log_label.log_label = fmt::to_string(buffer); + } template void log_debug(const char* fmt, Args&&... args) const @@ -195,8 +200,7 @@ class prefixed_logger private: srslog::basic_logger& logger; - Prefix prefix; - const char* prefix_separator; + srslog::log_label_t log_label; template void log_helper(srslog::log_channel& channel, const char* fmt, Args&&... args) const @@ -204,9 +208,7 @@ class prefixed_logger if (!channel.enabled()) { return; } - fmt::memory_buffer buffer; - fmt::format_to(buffer, fmt, std::forward(args)...); - channel("{}{}{}", prefix, prefix_separator, to_c_str(buffer)); + channel(log_label, fmt, std::forward(args)...); } template @@ -215,9 +217,7 @@ class prefixed_logger if (!channel.enabled()) { return; } - fmt::memory_buffer buffer; - fmt::format_to(buffer, fmt, std::forward(args)...); - channel(it_begin, it_end, "{}{}{}", prefix, prefix_separator, to_c_str(buffer)); + channel(log_label, it_begin, it_end, fmt, std::forward(args)...); } template @@ -226,9 +226,7 @@ class prefixed_logger if (!channel.enabled()) { return; } - fmt::memory_buffer buffer; - fmt::format_to(buffer, fmt, std::forward(args)...); - channel(msg, len, "{}{}{}", prefix, prefix_separator, to_c_str(buffer)); + channel(log_label, msg, len, fmt, std::forward(args)...); } }; diff --git a/lib/srslog/formatters/text_formatter.cpp b/lib/srslog/formatters/text_formatter.cpp index 1eafc05f90..ef6ff6f4fc 100644 --- a/lib/srslog/formatters/text_formatter.cpp +++ b/lib/srslog/formatters/text_formatter.cpp @@ -61,6 +61,9 @@ static void format_metadata(const detail::log_entry_metadata& metadata, fmt::mem ctx_buffer.push_back('\0'); fmt::format_to(buffer, "[{: >8}] ", ctx_buffer.data()); } + if (!metadata.log_label.empty()) { + fmt::format_to(buffer, "{}", metadata.log_label); + } } void text_formatter::format(detail::log_entry_metadata&& metadata, fmt::memory_buffer& buffer) From a6c471d7d14f799976a771d3f9b78228715d1cce Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Thu, 7 Mar 2024 12:58:57 +0100 Subject: [PATCH 137/140] srslog: pass log_label as shared_ptr --- .../srsran/srslog/detail/log_entry_metadata.h | 2 +- include/srsran/srslog/log_channel.h | 24 +++++++++---------- include/srsran/support/prefixed_logger.h | 6 ++--- lib/srslog/formatters/text_formatter.cpp | 4 ++-- 4 files changed, 17 insertions(+), 19 deletions(-) diff --git a/include/srsran/srslog/detail/log_entry_metadata.h b/include/srsran/srslog/detail/log_entry_metadata.h index 544efce6e3..1a79867412 100644 --- a/include/srsran/srslog/detail/log_entry_metadata.h +++ b/include/srsran/srslog/detail/log_entry_metadata.h @@ -34,7 +34,7 @@ struct log_entry_metadata { fmt::dynamic_format_arg_store* store; std::string log_name; char log_tag; - std::string log_label; + std::shared_ptr log_label; std::vector hex_dump; }; diff --git a/include/srsran/srslog/log_channel.h b/include/srsran/srslog/log_channel.h index 5e90ff720f..3a097a307b 100644 --- a/include/srsran/srslog/log_channel.h +++ b/include/srsran/srslog/log_channel.h @@ -44,13 +44,6 @@ struct log_channel_config { bool should_print_context = false; }; -/// Strong type to wrap a constant log label that is prepended to each log message. -struct log_label_t { - /// Optional log label. If set, will get printed in front of each log message. - /// Disabled by default. - std::string log_label; -}; - /// A log channel is the entity used for logging messages. /// /// It can deliver a log entry to one or more different sinks, for example a @@ -146,7 +139,7 @@ class log_channel /// Builds the provided log entry and passes it to the backend. When the /// channel is disabled the log entry will be discarded. template - void operator()(const log_label_t& label, const char* fmtstr, Args&&... args) + void operator()(std::shared_ptr log_label, const char* fmtstr, Args&&... args) { if (!enabled()) { return; @@ -171,7 +164,7 @@ class log_channel store, log_name, log_tag, - label.log_label}}; + std::move(log_label)}}; backend.push(std::move(entry)); } @@ -247,7 +240,11 @@ class log_channel /// Builds the provided log entry and passes it to the backend. When the /// channel is disabled the log entry will be discarded. template - void operator()(const log_label_t& label, const uint8_t* buffer, size_t len, const char* fmtstr, Args&&... args) + void operator()(std::shared_ptr log_label, + const uint8_t* buffer, + size_t len, + const char* fmtstr, + Args&&... args) { if (!enabled()) { return; @@ -277,7 +274,7 @@ class log_channel store, log_name, log_tag, - label.log_label, + std::move(log_label), std::vector(buffer, buffer + len)}}; backend.push(std::move(entry)); } @@ -361,7 +358,8 @@ class log_channel /// Builds the provided log entry and passes it to the backend. When the /// channel is disabled the log entry will be discarded. template ::value, int>::type = 0> - void operator()(const log_label_t& label, It it_begin, It it_end, const char* fmtstr, Args&&... args) + void + operator()(std::shared_ptr log_label, It it_begin, It it_end, const char* fmtstr, Args&&... args) { if (!enabled()) { return; @@ -391,7 +389,7 @@ class log_channel store, log_name, log_tag, - label.log_label, + std::move(log_label), std::vector(it_begin, it_end)}}; backend.push(std::move(entry)); } diff --git a/include/srsran/support/prefixed_logger.h b/include/srsran/support/prefixed_logger.h index 180781a064..98ea3037f2 100644 --- a/include/srsran/support/prefixed_logger.h +++ b/include/srsran/support/prefixed_logger.h @@ -35,7 +35,7 @@ class prefixed_logger { fmt::memory_buffer buffer; fmt::format_to(buffer, "{}{}", prefix, prefix_separator); - log_label.log_label = fmt::to_string(buffer); + log_label = std::make_shared(fmt::to_string(buffer)); } template @@ -199,8 +199,8 @@ class prefixed_logger srslog::basic_logger& get_basic_logger() { return logger; } private: - srslog::basic_logger& logger; - srslog::log_label_t log_label; + srslog::basic_logger& logger; + std::shared_ptr log_label; template void log_helper(srslog::log_channel& channel, const char* fmt, Args&&... args) const diff --git a/lib/srslog/formatters/text_formatter.cpp b/lib/srslog/formatters/text_formatter.cpp index ef6ff6f4fc..37bc38c611 100644 --- a/lib/srslog/formatters/text_formatter.cpp +++ b/lib/srslog/formatters/text_formatter.cpp @@ -61,8 +61,8 @@ static void format_metadata(const detail::log_entry_metadata& metadata, fmt::mem ctx_buffer.push_back('\0'); fmt::format_to(buffer, "[{: >8}] ", ctx_buffer.data()); } - if (!metadata.log_label.empty()) { - fmt::format_to(buffer, "{}", metadata.log_label); + if (metadata.log_label != nullptr && !metadata.log_label->empty()) { + fmt::format_to(buffer, "{}", *metadata.log_label); } } From 9f5746438bdcb40df8c0315aa8c7f4c4e7cca70d Mon Sep 17 00:00:00 2001 From: Oriol Font-Bach Date: Mon, 11 Mar 2024 12:08:07 +0000 Subject: [PATCH 138/140] hal: fixes external harq size request function, initializes private vector sizes --- include/srsran/hal/dpdk/bbdev/bbdev_acc.h | 4 ++-- .../pusch/ext_harq_buffer_context_repository.h | 7 ++++--- .../pusch/ext_harq_buffer_context_repository_factory.h | 2 +- lib/hal/dpdk/bbdev/ldpc/bbdev_ldpc_decoder.cpp | 2 +- .../pusch/ext_harq_buffer_context_repository_factory.cpp | 6 ++++-- lib/phy/upper/channel_processors/pdsch_encoder_hw_impl.cpp | 2 ++ .../upper/channel_processors/pusch/pusch_decoder_hw_impl.h | 1 + .../pusch/pusch_decoder_hwacc_benchmark.cpp | 2 +- .../channel_processors/pusch/pusch_processor_benchmark.cpp | 2 +- .../channel_processors/pusch/pusch_decoder_vectortest.cpp | 2 +- .../pusch/pusch_processor_vectortest.cpp | 2 +- 11 files changed, 19 insertions(+), 13 deletions(-) diff --git a/include/srsran/hal/dpdk/bbdev/bbdev_acc.h b/include/srsran/hal/dpdk/bbdev/bbdev_acc.h index 4109b885c1..7fc5e2cab3 100644 --- a/include/srsran/hal/dpdk/bbdev/bbdev_acc.h +++ b/include/srsran/hal/dpdk/bbdev/bbdev_acc.h @@ -78,8 +78,8 @@ class bbdev_acc unsigned get_nof_fft_cores() const { return nof_fft_lcores; } /// Returns the size of the (external) HARQ buffer size embedded in the hardware-accelerator. - /// \return HARQ buffer size (in bytes). - units::bytes get_harq_buff_size() const { return units::bytes(1024 * info.drv.harq_buffer_size); } + /// \return HARQ buffer size in bytes. Note that 64 bits are used to enable sizes >= 4GB. + uint64_t get_harq_buff_size_bytes() const { return static_cast(info.drv.harq_buffer_size) * 1024; } /// Returns the size of each mbuf used to exchange unencoded and unrate-matched messages with the accelerator. /// \return Unencoded and unrate-matched mbuf size (in bytes). diff --git a/include/srsran/hal/phy/upper/channel_processors/pusch/ext_harq_buffer_context_repository.h b/include/srsran/hal/phy/upper/channel_processors/pusch/ext_harq_buffer_context_repository.h index 76266f70aa..7149f32dbc 100644 --- a/include/srsran/hal/phy/upper/channel_processors/pusch/ext_harq_buffer_context_repository.h +++ b/include/srsran/hal/phy/upper/channel_processors/pusch/ext_harq_buffer_context_repository.h @@ -14,6 +14,7 @@ #pragma once #include "srsran/support/srsran_assert.h" +#include "srsran/support/units.h" #include namespace srsran { @@ -21,7 +22,7 @@ namespace hal { /// Fixed CB-offset increment used in the accelerator's HARQ memory. /// Note that it is assumed that the HARQ memory is organized in N slots of HARQ_INCR bytes. -static constexpr unsigned HARQ_INCR = 32768; +static constexpr units::bytes HARQ_INCR{32768}; /// External HARQ buffer context. struct ext_harq_buffer_context_entry { @@ -39,10 +40,10 @@ class ext_harq_buffer_context_repository /// \param[in] nof_codeblocks_ Indicates the number of codeblocks to store in the repository. /// \param[in] ext_harq_buff_size Size of the external HARQ buffer (in bytes). /// \param[in] debug_mode_ Requests to implement the debug mode (meant for unittesting). - explicit ext_harq_buffer_context_repository(unsigned nof_codeblocks_, unsigned ext_harq_buff_size, bool debug_mode_) : + explicit ext_harq_buffer_context_repository(unsigned nof_codeblocks_, uint64_t ext_harq_buff_size, bool debug_mode_) : nof_codeblocks(nof_codeblocks_) { - unsigned requested_size = nof_codeblocks_ * HARQ_INCR; + uint64_t requested_size = static_cast(nof_codeblocks_) * static_cast(HARQ_INCR.value()); srsran_assert(requested_size <= ext_harq_buff_size, "Requested size ({} bytes) for {} codeblocks exceeds external HARQ buffer capacity ({} bytes).", requested_size, diff --git a/include/srsran/hal/phy/upper/channel_processors/pusch/ext_harq_buffer_context_repository_factory.h b/include/srsran/hal/phy/upper/channel_processors/pusch/ext_harq_buffer_context_repository_factory.h index 197608264b..a6a354bbb8 100644 --- a/include/srsran/hal/phy/upper/channel_processors/pusch/ext_harq_buffer_context_repository_factory.h +++ b/include/srsran/hal/phy/upper/channel_processors/pusch/ext_harq_buffer_context_repository_factory.h @@ -18,7 +18,7 @@ namespace hal { /// Returns a ext_harq_buffer_context_repository instance on success, otherwise returns nullptr. std::shared_ptr create_ext_harq_buffer_context_repository(unsigned nof_codeblocks, - unsigned ext_harq_buff_size, + uint64_t ext_harq_buff_size, bool debug_mode = false); } // namespace hal diff --git a/lib/hal/dpdk/bbdev/ldpc/bbdev_ldpc_decoder.cpp b/lib/hal/dpdk/bbdev/ldpc/bbdev_ldpc_decoder.cpp index cfce2093e3..8473b318c2 100644 --- a/lib/hal/dpdk/bbdev/ldpc/bbdev_ldpc_decoder.cpp +++ b/lib/hal/dpdk/bbdev/ldpc/bbdev_ldpc_decoder.cpp @@ -131,7 +131,7 @@ bool dpdk::set_ldpc_dec_bbdev_data(::rte_bbdev_dec_op& dec_op, dec_op.ldpc_dec.input.length += cw_len; // Harq offset for the current CB (based on its unique absolute ID). - unsigned harq_offset = srsran::hal::HARQ_INCR * absolute_cb_id; + unsigned harq_offset = srsran::hal::HARQ_INCR.value() * absolute_cb_id; // Input HARQ combining data is only needed in case of a retransmission. if (!new_data) { diff --git a/lib/hal/phy/upper/channel_processors/pusch/ext_harq_buffer_context_repository_factory.cpp b/lib/hal/phy/upper/channel_processors/pusch/ext_harq_buffer_context_repository_factory.cpp index 393553af49..d1185b57e0 100644 --- a/lib/hal/phy/upper/channel_processors/pusch/ext_harq_buffer_context_repository_factory.cpp +++ b/lib/hal/phy/upper/channel_processors/pusch/ext_harq_buffer_context_repository_factory.cpp @@ -14,7 +14,9 @@ using namespace srsran; using namespace hal; std::shared_ptr -srsran::hal::create_ext_harq_buffer_context_repository(unsigned nof_rnti, unsigned nof_harq_id, bool debug_mode) +srsran::hal::create_ext_harq_buffer_context_repository(unsigned nof_codeblocks, + uint64_t ext_harq_buff_size, + bool debug_mode) { - return std::make_shared(nof_rnti, nof_harq_id, debug_mode); + return std::make_shared(nof_codeblocks, ext_harq_buff_size, debug_mode); } diff --git a/lib/phy/upper/channel_processors/pdsch_encoder_hw_impl.cpp b/lib/phy/upper/channel_processors/pdsch_encoder_hw_impl.cpp index 41e0a2c6f8..e313d887e5 100644 --- a/lib/phy/upper/channel_processors/pdsch_encoder_hw_impl.cpp +++ b/lib/phy/upper/channel_processors/pdsch_encoder_hw_impl.cpp @@ -120,8 +120,10 @@ void pdsch_encoder_hw_impl::encode(span codeword, srsran_assert(offset + rm_length <= codeword.size(), "Wrong codeword length."); codeblock = span(codeword).subspan(offset, rm_length); + codeblock_packed.resize(rm_length); } else { codeblock = codeword; + codeblock_packed.resize(codeword.size()); } // Make sure at least one operation is dequeued. diff --git a/lib/phy/upper/channel_processors/pusch/pusch_decoder_hw_impl.h b/lib/phy/upper/channel_processors/pusch/pusch_decoder_hw_impl.h index 3ff4688271..60447f0a29 100644 --- a/lib/phy/upper/channel_processors/pusch/pusch_decoder_hw_impl.h +++ b/lib/phy/upper/channel_processors/pusch/pusch_decoder_hw_impl.h @@ -73,6 +73,7 @@ class pusch_decoder_hw_impl : public pusch_decoder, private pusch_decoder_buffer srsran_assert(crc_set.crc24B->get_generator_poly() == crc_generator_poly::CRC24B, "Not a CRC generator of type CRC24B."); srsran_assert(decoder, "Invalid hardware-accelerated PUSCH decoder."); + absolute_cb_ids.resize(MAX_NOF_SEGMENTS); } // See interface for the documentation. diff --git a/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_decoder_hwacc_benchmark.cpp b/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_decoder_hwacc_benchmark.cpp index 114fcbb6a7..ff28cc76b3 100644 --- a/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_decoder_hwacc_benchmark.cpp +++ b/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_decoder_hwacc_benchmark.cpp @@ -206,7 +206,7 @@ static std::shared_ptr create_hw_accelera // Interfacing to a shared external HARQ buffer context repository. unsigned nof_cbs = MAX_NOF_SEGMENTS; - unsigned acc100_ext_harq_buff_size = bbdev_accelerator->get_harq_buff_size().value(); + uint64_t acc100_ext_harq_buff_size = bbdev_accelerator->get_harq_buff_size_bytes(); std::shared_ptr harq_buffer_context = create_ext_harq_buffer_context_repository(nof_cbs, acc100_ext_harq_buff_size, test_harq); TESTASSERT(harq_buffer_context); diff --git a/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_processor_benchmark.cpp b/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_processor_benchmark.cpp index e8ff28761a..f89381d193 100644 --- a/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_processor_benchmark.cpp +++ b/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_processor_benchmark.cpp @@ -489,7 +489,7 @@ static std::shared_ptr create_hw_accelera // Interfacing to a shared external HARQ buffer context repository. unsigned nof_cbs = MAX_NOF_SEGMENTS; - unsigned acc100_ext_harq_buff_size = bbdev_accelerator->get_harq_buff_size().value(); + uint64_t acc100_ext_harq_buff_size = bbdev_accelerator->get_harq_buff_size_bytes(); std::shared_ptr harq_buffer_context = create_ext_harq_buffer_context_repository(nof_cbs, acc100_ext_harq_buff_size, false); TESTASSERT(harq_buffer_context); diff --git a/tests/unittests/phy/upper/channel_processors/pusch/pusch_decoder_vectortest.cpp b/tests/unittests/phy/upper/channel_processors/pusch/pusch_decoder_vectortest.cpp index 9d1db7f683..fd87038763 100644 --- a/tests/unittests/phy/upper/channel_processors/pusch/pusch_decoder_vectortest.cpp +++ b/tests/unittests/phy/upper/channel_processors/pusch/pusch_decoder_vectortest.cpp @@ -187,7 +187,7 @@ static std::shared_ptr create_hw_accelera // Interfacing to a shared external HARQ buffer context repository. unsigned nof_cbs = MAX_NOF_SEGMENTS; - unsigned acc100_ext_harq_buff_size = bbdev_accelerator->get_harq_buff_size().value(); + uint64_t acc100_ext_harq_buff_size = bbdev_accelerator->get_harq_buff_size_bytes(); std::shared_ptr harq_buffer_context = create_ext_harq_buffer_context_repository(nof_cbs, acc100_ext_harq_buff_size, test_harq); TESTASSERT(harq_buffer_context); diff --git a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_vectortest.cpp b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_vectortest.cpp index 0775b0e509..7132e5b809 100644 --- a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_vectortest.cpp +++ b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_vectortest.cpp @@ -123,7 +123,7 @@ class PuschProcessorFixture : public ::testing::TestWithParamget_harq_buff_size().value(); + uint64_t acc100_ext_harq_buff_size = bbdev_accelerator->get_harq_buff_size_bytes(); std::shared_ptr harq_buffer_context = create_ext_harq_buffer_context_repository(nof_cbs, acc100_ext_harq_buff_size, false); if (!harq_buffer_context) { From 6886b4d340ee2584e4ac1fc5db704c4fb807b7b4 Mon Sep 17 00:00:00 2001 From: asaezper Date: Mon, 11 Mar 2024 12:36:39 +0100 Subject: [PATCH 139/140] ci,e2e: adjust retries and pcaps --- .gitlab/ci/e2e.yml | 2 +- tests/e2e/tests/attach_detach.py | 11 +++++------ tests/e2e/tests/iperf.py | 6 +++--- tests/e2e/tests/ping.py | 2 +- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index afa63823c0..49f81799ad 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -273,7 +273,7 @@ amari 32UE: variables: MARKERS: "zmq and not smoke" E2E_LOG_LEVEL: "info" - RETINA_ARGS: "gnb.all.pcap=True gnb.all.mac_enable=True gnb.all.rlc_enable=False" + RETINA_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False" needs: - job: "basic relwithdeb" artifacts: true diff --git a/tests/e2e/tests/attach_detach.py b/tests/e2e/tests/attach_detach.py index e184e1e028..5619091e38 100644 --- a/tests/e2e/tests/attach_detach.py +++ b/tests/e2e/tests/attach_detach.py @@ -44,14 +44,14 @@ ), ) @mark.parametrize( - "band, common_scs, bandwidth, always_download_artifacts", + "band, common_scs, bandwidth", ( - param(3, 15, 50, True, id="band:%s-scs:%s-bandwidth:%s-artifacts:%s"), - param(41, 30, 50, False, id="band:%s-scs:%s-bandwidth:%s-artifacts:%s"), + param(3, 15, 50, id="band:%s-scs:%s-bandwidth:%s"), + param(41, 30, 50, id="band:%s-scs:%s-bandwidth:%s"), ), ) @mark.zmq -@mark.flaky(reruns=3, only_rerun=["failed to start"]) +@mark.flaky(reruns=3, only_rerun=["failed to start", "IPerf Data Invalid"]) # pylint: disable=too-many-arguments def test_zmq( retina_manager: RetinaTestManager, @@ -62,7 +62,6 @@ def test_zmq( band: int, common_scs: int, bandwidth: int, - always_download_artifacts: bool, protocol: IPerfProto, direction: IPerfDir, ): @@ -86,7 +85,7 @@ def test_zmq( direction=direction, global_timing_advance=0, time_alignment_calibration=0, - always_download_artifacts=always_download_artifacts, + always_download_artifacts=False, ) diff --git a/tests/e2e/tests/iperf.py b/tests/e2e/tests/iperf.py index 1941e4fa4d..0bdc68b320 100644 --- a/tests/e2e/tests/iperf.py +++ b/tests/e2e/tests/iperf.py @@ -477,9 +477,9 @@ def test_zmq_smoke( ), ) @mark.zmq -# @mark.flaky( -# reruns=2, only_rerun=["failed to start", "Attach timeout reached", "iperf did not achieve the expected data rate"] -# ) +@mark.flaky( + reruns=2, only_rerun=["failed to start", "Attach timeout reached", "iperf did not achieve the expected data rate"] +) # pylint: disable=too-many-arguments def test_zmq( retina_manager: RetinaTestManager, diff --git a/tests/e2e/tests/ping.py b/tests/e2e/tests/ping.py index fafc9c2f30..9cc2d587d7 100644 --- a/tests/e2e/tests/ping.py +++ b/tests/e2e/tests/ping.py @@ -140,7 +140,7 @@ def test_android_hp( ), ) @mark.zmq -# @mark.flaky(reruns=2, only_rerun=["failed to start", "Attach timeout reached", "Some packages got lost"]) +@mark.flaky(reruns=2, only_rerun=["failed to start", "Attach timeout reached", "Some packages got lost"]) # pylint: disable=too-many-arguments def test_zmq( retina_manager: RetinaTestManager, From a5d53d90aacd50558aacdf3596168ef3fbb390e8 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Mon, 11 Mar 2024 13:36:40 +0100 Subject: [PATCH 140/140] docker: update open5GS to v2.6.6 --- docker/docker-compose.yml | 2 +- docker/open5gs/Dockerfile | 2 +- docker/open5gs/README.md | 4 ++-- docker/open5gs/open5gs-5gc.yml | 6 +++++- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index df9e91e95b..490086eda1 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -16,7 +16,7 @@ services: target: open5gs args: OS_VERSION: "22.04" - OPEN5GS_VERSION: "v2.6.1" + OPEN5GS_VERSION: "v2.6.6" env_file: - ${OPEN_5GS_ENV_FILE:-open5gs/open5gs.env} privileged: true diff --git a/docker/open5gs/Dockerfile b/docker/open5gs/Dockerfile index b5ccd71c21..5e7d7c0a06 100644 --- a/docker/open5gs/Dockerfile +++ b/docker/open5gs/Dockerfile @@ -62,7 +62,7 @@ RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y --no-ins && apt-get autoremove && apt-get clean # To set a fixed version of open5gs use -ARG OPEN5GS_VERSION=v2.6.1 +ARG OPEN5GS_VERSION=v2.6.6 RUN echo $OPEN5GS_VERSION > ./open5gsversion # get latest open5gs tag (must be stored in a file, because docker does not allow to use the return value directly) # RUN git ls-remote --tags https://github.com/open5gs/open5gs | sort -t '/' -k 3 -V | awk -F/ '{ print $3 }' | awk '!/\^\{\}/' | tail -n 1 > ./open5gsversion diff --git a/docker/open5gs/README.md b/docker/open5gs/README.md index 90a5fd4ee6..b8539a207b 100644 --- a/docker/open5gs/README.md +++ b/docker/open5gs/README.md @@ -1,4 +1,4 @@ -This is a all-in-one Docker container for Open5GS. At build, the container will use the specified version of the open5gs repository (default v2.6.1 +This is a all-in-one Docker container for Open5GS. At build, the container will use the specified version of the open5gs repository (default v2.6.6 ). To run the latest tag of the open5gs repository (), line 51 and 52 in .Dockerfile ``` # get latest open5gs tag (must be stored in a file, because docker does not allow to use the return value directly) @@ -54,7 +54,7 @@ Build the Docker container using: `docker build --target open5gs -t open5gs-docker .` -You can overwrite open5gs version by adding `--build-arg OPEN5GS_VERSION=v2.6.1` +You can overwrite open5gs version by adding `--build-arg OPEN5GS_VERSION=v2.6.6` Then run the docker container with: diff --git a/docker/open5gs/open5gs-5gc.yml b/docker/open5gs/open5gs-5gc.yml index a4d79ea6fa..d8d1e67041 100644 --- a/docker/open5gs/open5gs-5gc.yml +++ b/docker/open5gs/open5gs-5gc.yml @@ -26,7 +26,6 @@ parameter: # no_sgwu: true # no_pcrf: true # no_hss: true -no_ipv6: true sbi: server: @@ -242,3 +241,8 @@ udr: sbi: - addr: 127.0.0.20 port: 7777 +time: + t3412: + value: 540 # 9 minutes * 60 = 540 seconds + t3512: + value: 540 # 9 minutes * 60 = 540 seconds