From bb7339910fbdc9b705dbbe6341d9a6da554e2f49 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Mon, 7 Mar 2022 15:01:57 +0100 Subject: [PATCH] rlc: separate types of rlc_amd_retx_t for LTE and NR --- lib/include/srsran/rlc/rlc_am_data_structs.h | 24 ++++++++----- lib/include/srsran/rlc/rlc_am_lte.h | 6 ++-- lib/include/srsran/rlc/rlc_am_lte_packing.h | 2 +- lib/include/srsran/rlc/rlc_am_nr.h | 10 +++--- lib/src/rlc/rlc_am_lte.cc | 20 +++++------ lib/src/rlc/rlc_am_nr.cc | 37 ++++++++++---------- lib/test/rlc/rlc_am_nr_test.cc | 36 +++++++++---------- 7 files changed, 72 insertions(+), 63 deletions(-) diff --git a/lib/include/srsran/rlc/rlc_am_data_structs.h b/lib/include/srsran/rlc/rlc_am_data_structs.h index a9ce6cac5..f114a4a4d 100644 --- a/lib/include/srsran/rlc/rlc_am_data_structs.h +++ b/lib/include/srsran/rlc/rlc_am_data_structs.h @@ -300,7 +300,7 @@ private: uint32_t count = 0; }; -struct rlc_amd_retx_t { +struct rlc_amd_retx_lte_t { uint32_t sn; bool is_segment; uint32_t so_start; // offset to first byte of this segment @@ -308,21 +308,29 @@ struct rlc_amd_retx_t { uint32_t current_so; }; -template +struct rlc_amd_retx_nr_t { + uint32_t sn; + bool is_segment; + uint32_t so_start; // offset to first byte of this segment + uint32_t so_end; // offset to first byte beyond the end of this segment + uint32_t current_so; +}; + +template class pdu_retx_queue { public: - rlc_amd_retx_t& push() + T& push() { assert(not full()); - rlc_amd_retx_t& p = buffer[wpos]; + T& p = buffer[wpos]; wpos = (wpos + 1) % WINDOW_SIZE; return p; } void pop() { rpos = (rpos + 1) % WINDOW_SIZE; } - rlc_amd_retx_t& front() + T& front() { assert(not empty()); return buffer[rpos]; @@ -349,9 +357,9 @@ public: bool full() const { return size() == WINDOW_SIZE - 1; } private: - std::array buffer; - size_t wpos = 0; - size_t rpos = 0; + std::array buffer; + size_t wpos = 0; + size_t rpos = 0; }; } // namespace srsran diff --git a/lib/include/srsran/rlc/rlc_am_lte.h b/lib/include/srsran/rlc/rlc_am_lte.h index 90031dae8..f3500d48d 100644 --- a/lib/include/srsran/rlc/rlc_am_lte.h +++ b/lib/include/srsran/rlc/rlc_am_lte.h @@ -79,11 +79,11 @@ private: int build_status_pdu(uint8_t* payload, uint32_t nof_bytes); int build_retx_pdu(uint8_t* payload, uint32_t nof_bytes); - int build_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_retx_t retx); + int build_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_retx_lte_t retx); int build_data_pdu(uint8_t* payload, uint32_t nof_bytes); void update_notification_ack_info(uint32_t rlc_sn); - int required_buffer_size(const rlc_amd_retx_t& retx); + int required_buffer_size(const rlc_amd_retx_lte_t& retx); void retransmit_pdu(uint32_t sn); // Helpers @@ -137,7 +137,7 @@ private: // Tx windows rlc_ringbuffer_t, RLC_AM_WINDOW_SIZE> tx_window; - pdu_retx_queue retx_queue; + pdu_retx_queue retx_queue; pdcp_sn_vector_t notify_info_vec; // Mutexes diff --git a/lib/include/srsran/rlc/rlc_am_lte_packing.h b/lib/include/srsran/rlc/rlc_am_lte_packing.h index ea866bde8..6bb88d87e 100644 --- a/lib/include/srsran/rlc/rlc_am_lte_packing.h +++ b/lib/include/srsran/rlc/rlc_am_lte_packing.h @@ -53,7 +53,7 @@ int rlc_am_write_status_pdu(rlc_status_pdu_t* status, uint8_t* payload); uint32_t rlc_am_packed_length(rlc_amd_pdu_header_t* header); uint32_t rlc_am_packed_length(rlc_status_pdu_t* status); -uint32_t rlc_am_packed_length(rlc_amd_retx_t retx); +uint32_t rlc_am_packed_length(rlc_amd_retx_lte_t retx); bool rlc_am_is_pdu_segment(uint8_t* payload); bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status, uint32_t rx_win_min = 0); bool rlc_am_start_aligned(const uint8_t fi); diff --git a/lib/include/srsran/rlc/rlc_am_nr.h b/lib/include/srsran/rlc/rlc_am_nr.h index 09a31b44e..220d1a41e 100644 --- a/lib/include/srsran/rlc/rlc_am_nr.h +++ b/lib/include/srsran/rlc/rlc_am_nr.h @@ -107,10 +107,10 @@ public: uint32_t build_new_sdu_segment(rlc_amd_tx_pdu_nr& tx_pdu, uint8_t* payload, uint32_t nof_bytes); uint32_t build_continuation_sdu_segment(rlc_amd_tx_pdu_nr& tx_pdu, uint8_t* payload, uint32_t nof_bytes); uint32_t build_retx_pdu(uint8_t* payload, uint32_t nof_bytes); - uint32_t build_retx_pdu_without_segmentation(rlc_amd_retx_t& retx, uint8_t* payload, uint32_t nof_bytes); - uint32_t build_retx_pdu_with_segmentation(rlc_amd_retx_t& retx, uint8_t* payload, uint32_t nof_bytes); - bool is_retx_segmentation_required(const rlc_amd_retx_t& retx, uint32_t nof_bytes); - uint32_t get_retx_expected_hdr_len(const rlc_amd_retx_t& retx); + uint32_t build_retx_pdu_without_segmentation(rlc_amd_retx_nr_t& retx, uint8_t* payload, uint32_t nof_bytes); + uint32_t build_retx_pdu_with_segmentation(rlc_amd_retx_nr_t& retx, uint8_t* payload, uint32_t nof_bytes); + bool is_retx_segmentation_required(const rlc_amd_retx_nr_t& retx, uint32_t nof_bytes); + uint32_t get_retx_expected_hdr_len(const rlc_amd_retx_nr_t& retx); // Buffer State bool has_data() final; @@ -150,7 +150,7 @@ private: rlc_ringbuffer_t tx_window; // Queues and buffers - pdu_retx_queue retx_queue; + pdu_retx_queue retx_queue; uint32_t sdu_under_segmentation_sn = INVALID_RLC_SN; // SN of the SDU currently being segmented. pdcp_sn_vector_t notify_info_vec; diff --git a/lib/src/rlc/rlc_am_lte.cc b/lib/src/rlc/rlc_am_lte.cc index 097acc769..a7af7555a 100644 --- a/lib/src/rlc/rlc_am_lte.cc +++ b/lib/src/rlc/rlc_am_lte.cc @@ -223,7 +223,7 @@ void rlc_am_lte_tx::get_buffer_state_nolock(uint32_t& n_bytes_newtx, uint32_t& n // Bytes needed for retx if (not retx_queue.empty()) { - rlc_amd_retx_t& retx = retx_queue.front(); + rlc_amd_retx_lte_t& retx = retx_queue.front(); RlcDebug("Buffer state - retx - SN=%d, Segment: %s, %d:%d", retx.sn, retx.is_segment ? "true" : "false", @@ -353,11 +353,11 @@ void rlc_am_lte_tx::retransmit_pdu(uint32_t sn) RlcInfo("Schedule SN=%d for retx", pdu.rlc_sn); - rlc_amd_retx_t& retx = retx_queue.push(); - retx.is_segment = false; - retx.so_start = 0; - retx.so_end = pdu.buf->N_bytes; - retx.sn = pdu.rlc_sn; + rlc_amd_retx_lte_t& retx = retx_queue.push(); + retx.is_segment = false; + retx.so_start = 0; + retx.so_end = pdu.buf->N_bytes; + retx.sn = pdu.rlc_sn; } /**************************************************************************** @@ -443,7 +443,7 @@ int rlc_am_lte_tx::build_retx_pdu(uint8_t* payload, uint32_t nof_bytes) return -1; } - rlc_amd_retx_t retx = retx_queue.front(); + rlc_amd_retx_lte_t retx = retx_queue.front(); // Sanity check - drop any retx SNs not present in tx_window while (not tx_window.has_sn(retx.sn)) { @@ -516,7 +516,7 @@ int rlc_am_lte_tx::build_retx_pdu(uint8_t* payload, uint32_t nof_bytes) return (ptr - payload) + tx_window[retx.sn].buf->N_bytes; } -int rlc_am_lte_tx::build_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_retx_t retx) +int rlc_am_lte_tx::build_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_retx_lte_t retx) { if (tx_window[retx.sn].buf == NULL) { RlcError("In build_segment: retx.sn=%d has null buffer", retx.sn); @@ -956,7 +956,7 @@ void rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes) pdu.retx_count++; check_sn_reached_max_retx(i); - rlc_amd_retx_t& retx = retx_queue.push(); + rlc_amd_retx_lte_t& retx = retx_queue.push(); srsran_expect(tx_window[i].rlc_sn == i, "Incorrect RLC SN=%d!=%d being accessed", tx_window[i].rlc_sn, i); retx.sn = i; retx.is_segment = false; @@ -1080,7 +1080,7 @@ void rlc_am_lte_tx::debug_state() RlcDebug("vt_a = %d, vt_ms = %d, vt_s = %d, poll_sn = %d", vt_a, vt_ms, vt_s, poll_sn); } -int rlc_am_lte_tx::required_buffer_size(const rlc_amd_retx_t& retx) +int rlc_am_lte_tx::required_buffer_size(const rlc_amd_retx_lte_t& retx) { if (!retx.is_segment) { if (tx_window.has_sn(retx.sn)) { diff --git a/lib/src/rlc/rlc_am_nr.cc b/lib/src/rlc/rlc_am_nr.cc index 8eead146b..78e378bc7 100644 --- a/lib/src/rlc/rlc_am_nr.cc +++ b/lib/src/rlc/rlc_am_nr.cc @@ -404,7 +404,7 @@ uint32_t rlc_am_nr_tx::build_retx_pdu(uint8_t* payload, uint32_t nof_bytes) return 0; } - rlc_amd_retx_t& retx = retx_queue.front(); + rlc_amd_retx_nr_t& retx = retx_queue.front(); // Sanity check - drop any retx SNs not present in tx_window while (not tx_window.has_sn(retx.sn)) { @@ -447,7 +447,8 @@ uint32_t rlc_am_nr_tx::build_retx_pdu(uint8_t* payload, uint32_t nof_bytes) * \remark this function will not update the SI. This means that if the retx is of the last * SDU segment, the SI should already be of the `last_segment` type. */ -uint32_t rlc_am_nr_tx::build_retx_pdu_without_segmentation(rlc_amd_retx_t& retx, uint8_t* payload, uint32_t nof_bytes) +uint32_t +rlc_am_nr_tx::build_retx_pdu_without_segmentation(rlc_amd_retx_nr_t& retx, uint8_t* payload, uint32_t nof_bytes) { srsran_assert(tx_window.has_sn(retx.sn), "Called %s without checking retx SN", __FUNCTION__); srsran_assert(not is_retx_segmentation_required(retx, nof_bytes), @@ -536,7 +537,7 @@ uint32_t rlc_am_nr_tx::build_retx_pdu_without_segmentation(rlc_amd_retx_t& retx, * \returns the number of bytes written to the payload buffer. * \remark: This functions assumes that the SDU has already been copied to tx_pdu.sdu_buf. */ -uint32_t rlc_am_nr_tx::build_retx_pdu_with_segmentation(rlc_amd_retx_t& retx, uint8_t* payload, uint32_t nof_bytes) +uint32_t rlc_am_nr_tx::build_retx_pdu_with_segmentation(rlc_amd_retx_nr_t& retx, uint8_t* payload, uint32_t nof_bytes) { // Get tx_pdu info from tx_window srsran_assert(tx_window.has_sn(retx.sn), "Called %s without checking retx SN", __FUNCTION__); @@ -633,7 +634,7 @@ uint32_t rlc_am_nr_tx::build_retx_pdu_with_segmentation(rlc_amd_retx_t& retx, ui return hdr_len + retx_pdu_payload_size; } -bool rlc_am_nr_tx::is_retx_segmentation_required(const rlc_amd_retx_t& retx, uint32_t nof_bytes) +bool rlc_am_nr_tx::is_retx_segmentation_required(const rlc_amd_retx_nr_t& retx, uint32_t nof_bytes) { bool segmentation_required = false; if (retx.is_segment) { @@ -651,7 +652,7 @@ bool rlc_am_nr_tx::is_retx_segmentation_required(const rlc_amd_retx_t& retx, uin return segmentation_required; } -uint32_t rlc_am_nr_tx::get_retx_expected_hdr_len(const rlc_amd_retx_t& retx) +uint32_t rlc_am_nr_tx::get_retx_expected_hdr_len(const rlc_amd_retx_nr_t& retx) { uint32_t expected_hdr_len = min_hdr_size; if (retx.is_segment && retx.current_so != 0) { @@ -748,12 +749,12 @@ void rlc_am_nr_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes) segm++) { if (segm->so >= nack.so_start && segm->so <= nack.so_end) { // TODO: Check if this segment is not already queued for retransmission - rlc_amd_retx_t& retx = retx_queue.push(); - retx.sn = nack_sn; - retx.is_segment = true; - retx.so_start = segm->so; - retx.current_so = segm->so; - retx.so_end = segm->so + segm->payload_len; + rlc_amd_retx_nr_t& retx = retx_queue.push(); + retx.sn = nack_sn; + retx.is_segment = true; + retx.so_start = segm->so; + retx.current_so = segm->so; + retx.so_end = segm->so + segm->payload_len; retx_sn_set.insert(nack_sn); RlcInfo( "Scheduled RETX of SDU segment SN=%d, so_start=%d, so_end=%d", retx.sn, retx.so_start, retx.so_end); @@ -763,12 +764,12 @@ void rlc_am_nr_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes) // NACK'ing full SDU. // add to retx queue if it's not already there if (not retx_queue.has_sn(nack_sn)) { - rlc_amd_retx_t& retx = retx_queue.push(); - retx.sn = nack_sn; - retx.is_segment = false; - retx.so_start = 0; - retx.current_so = 0; - retx.so_end = pdu.sdu_buf->N_bytes; + rlc_amd_retx_nr_t& retx = retx_queue.push(); + retx.sn = nack_sn; + retx.is_segment = false; + retx.so_start = 0; + retx.current_so = 0; + retx.so_end = pdu.sdu_buf->N_bytes; retx_sn_set.insert(nack_sn); RlcInfo("Scheduled RETX of SDU SN=%d", retx.sn); } @@ -847,7 +848,7 @@ void rlc_am_nr_tx::get_buffer_state(uint32_t& n_bytes_new, uint32_t& n_bytes_pri // Bytes needed for retx if (not retx_queue.empty()) { - rlc_amd_retx_t& retx = retx_queue.front(); + rlc_amd_retx_nr_t& retx = retx_queue.front(); RlcDebug("buffer state - retx - SN=%d, Segment: %s, %d:%d", retx.sn, retx.is_segment ? "true" : "false", diff --git a/lib/test/rlc/rlc_am_nr_test.cc b/lib/test/rlc/rlc_am_nr_test.cc index 3b8a16be6..1f841712d 100644 --- a/lib/test/rlc/rlc_am_nr_test.cc +++ b/lib/test/rlc/rlc_am_nr_test.cc @@ -147,10 +147,10 @@ int retx_segmentation_required_checker_test() // Test full SDU retx { - uint32_t nof_bytes = 8; - rlc_amd_retx_t retx = {}; - retx.sn = 0; - retx.is_segment = false; + uint32_t nof_bytes = 8; + rlc_amd_retx_nr_t retx = {}; + retx.sn = 0; + retx.is_segment = false; tx->is_retx_segmentation_required(retx, nof_bytes); TESTASSERT_EQ(false, tx->is_retx_segmentation_required(retx, nof_bytes)); @@ -158,8 +158,8 @@ int retx_segmentation_required_checker_test() // Test SDU retx segmentation required { - uint32_t nof_bytes = 4; - rlc_amd_retx_t retx; + uint32_t nof_bytes = 4; + rlc_amd_retx_nr_t retx; retx.sn = 0; retx.is_segment = false; @@ -169,12 +169,12 @@ int retx_segmentation_required_checker_test() // Test full SDU segment retx { - uint32_t nof_bytes = 40; - rlc_amd_retx_t retx = {}; - retx.sn = 0; - retx.is_segment = true; - retx.so_start = 4; - retx.so_end = 6; + uint32_t nof_bytes = 40; + rlc_amd_retx_nr_t retx = {}; + retx.sn = 0; + retx.is_segment = true; + retx.so_start = 4; + retx.so_end = 6; tx->is_retx_segmentation_required(retx, nof_bytes); TESTASSERT_EQ(false, tx->is_retx_segmentation_required(retx, nof_bytes)); @@ -182,12 +182,12 @@ int retx_segmentation_required_checker_test() // Test SDU segment retx segmentation required { - uint32_t nof_bytes = 4; - rlc_amd_retx_t retx = {}; - retx.sn = 0; - retx.is_segment = true; - retx.so_start = 4; - retx.so_end = 6; + uint32_t nof_bytes = 4; + rlc_amd_retx_nr_t retx = {}; + retx.sn = 0; + retx.is_segment = true; + retx.so_start = 4; + retx.so_end = 6; tx->is_retx_segmentation_required(retx, nof_bytes); TESTASSERT_EQ(true, tx->is_retx_segmentation_required(retx, nof_bytes));