From debb4a0c6b1fde7712a95d5c40a991f9984dd7b1 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Wed, 4 Aug 2021 12:43:41 +0100 Subject: [PATCH] Refactored RLC AM segment pool for re-use in both LTE and NR Moved RLC AMD PDU definitions from rlc_am_lte.h to rlc_common.h to make them re-usable in both RLC LTE and RLC NR --- lib/include/srsran/rlc/rlc_am_data_structs.h | 152 +++++++++++++++---- lib/include/srsran/rlc/rlc_am_lte.h | 14 +- lib/include/srsran/rlc/rlc_am_lte_packing.h | 55 ++----- lib/include/srsran/rlc/rlc_am_nr.h | 5 + lib/include/srsran/rlc/rlc_common.h | 5 +- lib/src/rlc/rlc_am_lte.cc | 76 +--------- lib/src/rlc/rlc_am_lte_packing.cc | 3 +- 7 files changed, 159 insertions(+), 151 deletions(-) diff --git a/lib/include/srsran/rlc/rlc_am_data_structs.h b/lib/include/srsran/rlc/rlc_am_data_structs.h index 2a5800125..465d466d0 100644 --- a/lib/include/srsran/rlc/rlc_am_data_structs.h +++ b/lib/include/srsran/rlc/rlc_am_data_structs.h @@ -16,61 +16,139 @@ #include "srsran/adt/circular_buffer.h" #include "srsran/adt/circular_map.h" #include "srsran/adt/intrusive_list.h" +#include "srsran/common/buffer_pool.h" #include #include namespace srsran { +template class rlc_amd_tx_pdu; +template class pdcp_pdu_info; /// Pool that manages the allocation of RLC AM PDU Segments to RLC PDUs and tracking of segments ACK state +template struct rlc_am_pdu_segment_pool { const static size_t MAX_POOL_SIZE = 16384; - using rlc_list_tag = default_intrusive_tag; - struct free_list_tag {}; /// RLC AM PDU Segment, containing the PDCP SN and RLC SN it has been assigned to, and its current ACK state + using rlc_list_tag = default_intrusive_tag; + struct free_list_tag {}; struct segment_resource : public intrusive_forward_list_element, public intrusive_forward_list_element, public intrusive_double_linked_list_element<> { const static uint32_t invalid_rlc_sn = std::numeric_limits::max(); const static uint32_t invalid_pdcp_sn = std::numeric_limits::max() - 1; // -1 for Status Report - int id() const; - void release_pdcp_sn(); - void release_rlc_sn(); + int id() const { return std::distance(parent_pool->segments.cbegin(), this); } + + void release_pdcp_sn() + { + pdcp_sn_ = invalid_pdcp_sn; + if (empty()) { + parent_pool->free_list.push_front(this); + } + } + + void release_rlc_sn() + { + rlc_sn_ = invalid_rlc_sn; + if (empty()) { + parent_pool->free_list.push_front(this); + } + } + uint32_t rlc_sn() const { return rlc_sn_; } uint32_t pdcp_sn() const { return pdcp_sn_; } bool empty() const { return rlc_sn_ == invalid_rlc_sn and pdcp_sn_ == invalid_pdcp_sn; } private: - friend struct rlc_am_pdu_segment_pool; - uint32_t rlc_sn_ = invalid_rlc_sn; - uint32_t pdcp_sn_ = invalid_pdcp_sn; - rlc_am_pdu_segment_pool* parent_pool = nullptr; + friend struct rlc_am_pdu_segment_pool; + uint32_t rlc_sn_ = invalid_rlc_sn; + uint32_t pdcp_sn_ = invalid_pdcp_sn; + rlc_am_pdu_segment_pool* parent_pool = nullptr; }; - rlc_am_pdu_segment_pool(); + rlc_am_pdu_segment_pool() + { + for (segment_resource& s : segments) { + s.parent_pool = this; + free_list.push_front(&s); + } + } rlc_am_pdu_segment_pool(const rlc_am_pdu_segment_pool&) = delete; rlc_am_pdu_segment_pool(rlc_am_pdu_segment_pool&&) = delete; rlc_am_pdu_segment_pool& operator=(const rlc_am_pdu_segment_pool&) = delete; rlc_am_pdu_segment_pool& operator=(rlc_am_pdu_segment_pool&&) = delete; - bool has_segments() const { return not free_list.empty(); } - bool make_segment(rlc_amd_tx_pdu& rlc_list, pdcp_pdu_info& pdcp_info); + + bool has_segments() const { return not free_list.empty(); } + bool make_segment(rlc_amd_tx_pdu& rlc_list, pdcp_pdu_info& pdcp_list) + { + if (not has_segments()) { + return false; + } + segment_resource* segment = free_list.pop_front(); + segment->rlc_sn_ = rlc_list.rlc_sn; + segment->pdcp_sn_ = pdcp_list.sn; + rlc_list.add_segment(*segment); + pdcp_list.add_segment(*segment); + return true; + } private: - intrusive_forward_list free_list; - std::array segments; + intrusive_forward_list::segment_resource, free_list_tag> free_list; + std::array::segment_resource, MAX_POOL_SIZE> segments; }; -/// RLC AM PDU Segment, containing the PDCP SN and RLC SN it has been assigned to, and its current ACK state -using rlc_am_pdu_segment = rlc_am_pdu_segment_pool::segment_resource; +/// Class that contains the parameters and state (e.g. segments) of a RLC PDU +template +class rlc_amd_tx_pdu +{ + using rlc_am_pdu_segment = typename rlc_am_pdu_segment_pool::segment_resource; + using list_type = intrusive_forward_list; + const static uint32_t invalid_rlc_sn = std::numeric_limits::max(); + + list_type list; + +public: + using iterator = typename list_type::iterator; + using const_iterator = typename list_type::const_iterator; + + const uint32_t rlc_sn = invalid_rlc_sn; + uint32_t retx_count = 0; + header_t header; + unique_byte_buffer_t buf; + + explicit rlc_amd_tx_pdu(uint32_t rlc_sn_) : rlc_sn(rlc_sn_) {} + rlc_amd_tx_pdu(const rlc_amd_tx_pdu&) = delete; + rlc_amd_tx_pdu(rlc_amd_tx_pdu&& other) noexcept = default; + rlc_amd_tx_pdu& operator=(const rlc_amd_tx_pdu& other) = delete; + rlc_amd_tx_pdu& operator=(rlc_amd_tx_pdu&& other) = delete; + ~rlc_amd_tx_pdu() + { + while (not list.empty()) { + // remove from list + rlc_am_pdu_segment* segment = list.pop_front(); + // deallocate if also removed from PDCP + segment->release_rlc_sn(); + } + } + + // Segment List Interface + void add_segment(rlc_am_pdu_segment& segment) { list.push_front(&segment); } + const_iterator begin() const { return list.begin(); } + const_iterator end() const { return list.end(); } + iterator begin() { return list.begin(); } + iterator end() { return list.end(); } +}; /// Class that contains the parameters and state (e.g. unACKed segments) of a PDCP PDU +template class pdcp_pdu_info { - using list_type = intrusive_double_linked_list; + using rlc_am_pdu_segment = typename rlc_am_pdu_segment_pool::segment_resource; + using list_type = intrusive_double_linked_list; list_type list; // List of unACKed RLC PDUs that contain segments that belong to the PDCP PDU. @@ -97,7 +175,13 @@ public: // Interface for list of unACKed RLC segments of the PDCP PDU void add_segment(rlc_am_pdu_segment& segment) { list.push_front(&segment); } - void ack_segment(rlc_am_pdu_segment& segment); + void ack_segment(rlc_am_pdu_segment& segment) + { + // remove from list + list.pop(&segment); + // signal pool that the pdcp handle is released + segment.release_pdcp_sn(); + } void clear() { sn = invalid_pdcp_sn; @@ -106,6 +190,7 @@ public: ack_segment(list.front()); } } + const_iterator begin() const { return list.begin(); } const_iterator end() const { return list.end(); } }; @@ -146,6 +231,7 @@ private: srsran::static_circular_map window; }; +template struct buffered_pdcp_pdu_list { public: explicit buffered_pdcp_pdu_list() : buffered_pdus(buffered_pdcp_pdu_list::buffer_size) { clear(); } @@ -153,7 +239,7 @@ public: void clear() { count = 0; - for (pdcp_pdu_info& b : buffered_pdus) { + for (pdcp_pdu_info& b : buffered_pdus) { b.clear(); } } @@ -162,7 +248,7 @@ public: { srsran_expect(sn <= max_pdcp_sn or sn == status_report_sn, "Invalid PDCP SN=%d", sn); srsran_assert(not has_pdcp_sn(sn), "Cannot re-add same PDCP SN twice"); - pdcp_pdu_info& pdu = get_pdu_(sn); + pdcp_pdu_info& pdu = get_pdu_(sn); if (pdu.valid()) { pdu.clear(); count--; @@ -170,21 +256,25 @@ public: pdu.sn = sn; count++; } + void clear_pdcp_sdu(uint32_t sn) { - pdcp_pdu_info& pdu = get_pdu_(sn); + pdcp_pdu_info& pdu = get_pdu_(sn); if (not pdu.valid()) { - return; + { + return; + } + pdu.clear(); + count--; } - pdu.clear(); - count--; } - pdcp_pdu_info& operator[](uint32_t sn) + pdcp_pdu_info& operator[](uint32_t sn) { srsran_expect(has_pdcp_sn(sn), "Invalid access to non-existent PDCP SN=%d", sn); return get_pdu_(sn); } + bool has_pdcp_sn(uint32_t pdcp_sn) const { srsran_expect(pdcp_sn <= max_pdcp_sn or pdcp_sn == status_report_sn, "Invalid PDCP SN=%d", pdcp_sn); @@ -195,21 +285,21 @@ public: private: const static size_t max_pdcp_sn = 262143u; const static size_t buffer_size = 4096u; - const static uint32_t status_report_sn = pdcp_pdu_info::status_report_sn; + const static uint32_t status_report_sn = pdcp_pdu_info::status_report_sn; - pdcp_pdu_info& get_pdu_(uint32_t sn) + pdcp_pdu_info& get_pdu_(uint32_t sn) { return (sn == status_report_sn) ? status_report_pdu : buffered_pdus[static_cast(sn % buffer_size)]; } - const pdcp_pdu_info& get_pdu_(uint32_t sn) const + const pdcp_pdu_info& get_pdu_(uint32_t sn) const { return (sn == status_report_sn) ? status_report_pdu : buffered_pdus[static_cast(sn % buffer_size)]; } // size equal to buffer_size - std::vector buffered_pdus; - pdcp_pdu_info status_report_pdu; - uint32_t count = 0; + std::vector > buffered_pdus; + pdcp_pdu_info status_report_pdu; + uint32_t count = 0; }; } // namespace srsran diff --git a/lib/include/srsran/rlc/rlc_am_lte.h b/lib/include/srsran/rlc/rlc_am_lte.h index 0fb69324d..6c6aeb4b7 100644 --- a/lib/include/srsran/rlc/rlc_am_lte.h +++ b/lib/include/srsran/rlc/rlc_am_lte.h @@ -143,9 +143,9 @@ public: void check_sn_reached_max_retx(uint32_t sn); void get_buffer_state_nolock(uint32_t& new_tx, uint32_t& prio_tx); - rlc_am_lte* parent = nullptr; - byte_buffer_pool* pool = nullptr; - rlc_am_pdu_segment_pool segment_pool; + rlc_am_lte* parent = nullptr; + byte_buffer_pool* pool = nullptr; + rlc_am_pdu_segment_pool segment_pool; /**************************************************************************** * Configurable parameters @@ -183,12 +183,12 @@ public: srsran::timer_handler::unique_timer status_prohibit_timer; // SDU info for PDCP notifications - buffered_pdcp_pdu_list undelivered_sdu_info_queue; + buffered_pdcp_pdu_list undelivered_sdu_info_queue; // Tx windows - rlc_ringbuffer_t tx_window; - pdu_retx_queue retx_queue; - pdcp_sn_vector_t notify_info_vec; + rlc_ringbuffer_t, RLC_AM_WINDOW_SIZE> tx_window; + pdu_retx_queue retx_queue; + pdcp_sn_vector_t notify_info_vec; // Mutexes std::mutex mutex; diff --git a/lib/include/srsran/rlc/rlc_am_lte_packing.h b/lib/include/srsran/rlc/rlc_am_lte_packing.h index 19215d4e4..e9ae3e8d4 100644 --- a/lib/include/srsran/rlc/rlc_am_lte_packing.h +++ b/lib/include/srsran/rlc/rlc_am_lte_packing.h @@ -20,38 +20,6 @@ namespace srsran { -/// Class that contains the parameters and state (e.g. segments) of a RLC PDU -class rlc_amd_tx_pdu -{ - using list_type = intrusive_forward_list; - const static uint32_t invalid_rlc_sn = std::numeric_limits::max(); - - list_type list; - -public: - using iterator = typename list_type::iterator; - using const_iterator = typename list_type::const_iterator; - - const uint32_t rlc_sn = invalid_rlc_sn; - uint32_t retx_count = 0; - rlc_amd_pdu_header_t header; - unique_byte_buffer_t buf; - - explicit rlc_amd_tx_pdu(uint32_t rlc_sn_) : rlc_sn(rlc_sn_) {} - rlc_amd_tx_pdu(const rlc_amd_tx_pdu&) = delete; - rlc_amd_tx_pdu(rlc_amd_tx_pdu&& other) noexcept = default; - rlc_amd_tx_pdu& operator=(const rlc_amd_tx_pdu& other) = delete; - rlc_amd_tx_pdu& operator=(rlc_amd_tx_pdu&& other) = delete; - ~rlc_amd_tx_pdu(); - - // Segment List Interface - void add_segment(rlc_am_pdu_segment& segment) { list.push_front(&segment); } - const_iterator begin() const { return list.begin(); } - const_iterator end() const { return list.end(); } - iterator begin() { return list.begin(); } - iterator end() { return list.end(); } -}; - struct rlc_amd_retx_t { uint32_t sn; bool is_segment; @@ -90,17 +58,18 @@ void rlc_am_read_status_pdu(uint8_t* payload, uint32_t nof_bytes, rlc_status_pdu void rlc_am_write_status_pdu(rlc_status_pdu_t* status, byte_buffer_t* pdu); 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); -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); -std::string rlc_am_undelivered_sdu_info_to_string(const std::map& info_queue); -void log_rlc_amd_pdu_header_to_string(srslog::log_channel& log_ch, const rlc_amd_pdu_header_t& header); -bool rlc_am_start_aligned(const uint8_t fi); -bool rlc_am_end_aligned(const uint8_t fi); -bool rlc_am_is_unaligned(const uint8_t fi); -bool rlc_am_not_start_aligned(const uint8_t fi); +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); +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); +std::string + rlc_am_undelivered_sdu_info_to_string(const std::map >& info_queue); +void log_rlc_amd_pdu_header_to_string(srslog::log_channel& log_ch, const rlc_amd_pdu_header_t& header); +bool rlc_am_start_aligned(const uint8_t fi); +bool rlc_am_end_aligned(const uint8_t fi); +bool rlc_am_is_unaligned(const uint8_t fi); +bool rlc_am_not_start_aligned(const uint8_t fi); /** * Logs Status PDU into provided log channel, using fmt_str as format string diff --git a/lib/include/srsran/rlc/rlc_am_nr.h b/lib/include/srsran/rlc/rlc_am_nr.h index 92f9d531a..3c8724742 100644 --- a/lib/include/srsran/rlc/rlc_am_nr.h +++ b/lib/include/srsran/rlc/rlc_am_nr.h @@ -17,6 +17,8 @@ #include "srsran/common/common.h" #include "srsran/common/timers.h" #include "srsran/rlc/rlc_am_base.h" +#include "srsran/rlc/rlc_am_data_structs.h" +#include "srsran/rlc/rlc_am_nr_packing.h" #include "srsran/upper/byte_buffer_queue.h" #include #include @@ -82,6 +84,9 @@ public: uint32_t pdu_without_poll; uint32_t byte_without_poll; } st = {}; + + using rlc_amd_tx_pdu_nr = rlc_amd_tx_pdu; + rlc_ringbuffer_t tx_window; }; // Receiver sub-class diff --git a/lib/include/srsran/rlc/rlc_common.h b/lib/include/srsran/rlc/rlc_common.h index bb5848e2c..9d6b0f29f 100644 --- a/lib/include/srsran/rlc/rlc_common.h +++ b/lib/include/srsran/rlc/rlc_common.h @@ -14,10 +14,13 @@ #define SRSRAN_RLC_COMMON_H #include "srsran/adt/circular_buffer.h" +#include "srsran/adt/circular_map.h" +#include "srsran/adt/intrusive_list.h" #include "srsran/interfaces/rlc_interface_types.h" #include "srsran/rlc/bearer_mem_pool.h" #include "srsran/rlc/rlc_metrics.h" -#include +#include +#include namespace srsran { diff --git a/lib/src/rlc/rlc_am_lte.cc b/lib/src/rlc/rlc_am_lte.cc index 209fb30d0..1cc5ed7e2 100644 --- a/lib/src/rlc/rlc_am_lte.cc +++ b/lib/src/rlc/rlc_am_lte.cc @@ -25,69 +25,9 @@ namespace srsran { -/******************************* - * RLC AM Segments - ******************************/ - -int rlc_am_pdu_segment_pool::segment_resource::id() const -{ - return std::distance(parent_pool->segments.cbegin(), this); -} - -void rlc_am_pdu_segment_pool::segment_resource::release_pdcp_sn() -{ - pdcp_sn_ = invalid_pdcp_sn; - if (empty()) { - parent_pool->free_list.push_front(this); - } -} - -void rlc_am_pdu_segment_pool::segment_resource::release_rlc_sn() -{ - rlc_sn_ = invalid_rlc_sn; - if (empty()) { - parent_pool->free_list.push_front(this); - } -} - -rlc_am_pdu_segment_pool::rlc_am_pdu_segment_pool() -{ - for (segment_resource& s : segments) { - s.parent_pool = this; - free_list.push_front(&s); - } -} - -bool rlc_am_pdu_segment_pool::make_segment(rlc_amd_tx_pdu& rlc_list, pdcp_pdu_info& pdcp_list) -{ - if (not has_segments()) { - return false; - } - segment_resource* segment = free_list.pop_front(); - segment->rlc_sn_ = rlc_list.rlc_sn; - segment->pdcp_sn_ = pdcp_list.sn; - rlc_list.add_segment(*segment); - pdcp_list.add_segment(*segment); - return true; -} - -void pdcp_pdu_info::ack_segment(rlc_am_pdu_segment& segment) -{ - // remove from list - list.pop(&segment); - // signal pool that the pdcp handle is released - segment.release_pdcp_sn(); -} - -rlc_amd_tx_pdu::~rlc_amd_tx_pdu() -{ - while (not list.empty()) { - // remove from list - rlc_am_pdu_segment* segment = list.pop_front(); - // deallocate if also removed from PDCP - segment->release_rlc_sn(); - } -} +using pdcp_pdu_info_lte = pdcp_pdu_info; +using rlc_amd_tx_pdu_lte = rlc_amd_tx_pdu; +using rlc_am_pdu_segment = rlc_am_pdu_segment_pool::segment_resource; /**************************************************************************** * RLC AM LTE entity @@ -432,7 +372,7 @@ void rlc_am_lte::rlc_am_lte_tx::retransmit_pdu(uint32_t sn) } // select first PDU in tx window for retransmission - rlc_amd_tx_pdu& pdu = tx_window[sn]; + rlc_amd_tx_pdu_lte& pdu = tx_window[sn]; // increment retx counter and inform upper layers pdu.retx_count++; @@ -823,7 +763,7 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt // insert newly assigned SN into window and use reference for in-place operations // NOTE: from now on, we can't return from this function anymore before increasing vt_s - rlc_amd_tx_pdu& tx_pdu = tx_window.add_pdu(header.sn); + rlc_amd_tx_pdu_lte& tx_pdu = tx_window.add_pdu(header.sn); uint32_t head_len = rlc_am_packed_length(&header); uint32_t to_move = 0; @@ -843,7 +783,7 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt tx_sdu->N_bytes -= to_move; tx_sdu->msg += to_move; if (undelivered_sdu_info_queue.has_pdcp_sn(tx_sdu->md.pdcp_sn)) { - pdcp_pdu_info& pdcp_pdu = undelivered_sdu_info_queue[tx_sdu->md.pdcp_sn]; + pdcp_pdu_info_lte& pdcp_pdu = undelivered_sdu_info_queue[tx_sdu->md.pdcp_sn]; segment_pool.make_segment(tx_pdu, pdcp_pdu); if (tx_sdu->N_bytes == 0) { pdcp_pdu.fully_txed = true; @@ -914,7 +854,7 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt undelivered_sdu_info_queue.nof_sdus()); undelivered_sdu_info_queue.add_pdcp_sdu(tx_sdu->md.pdcp_sn); } - pdcp_pdu_info& pdcp_pdu = undelivered_sdu_info_queue[tx_sdu->md.pdcp_sn]; + pdcp_pdu_info_lte& pdcp_pdu = undelivered_sdu_info_queue[tx_sdu->md.pdcp_sn]; to_move = ((pdu_space - head_len) >= tx_sdu->N_bytes) ? tx_sdu->N_bytes : pdu_space - head_len; memcpy(pdu_ptr, tx_sdu->msg, to_move); @@ -1155,7 +1095,7 @@ void rlc_am_lte::rlc_am_lte_tx::update_notification_ack_info(uint32_t rlc_sn) logger->debug("ACKed segment in RLC_SN=%d already discarded in PDCP. No need to notify the PDCP.", rlc_sn); continue; } - pdcp_pdu_info& info = undelivered_sdu_info_queue[pdcp_sn]; + pdcp_pdu_info_lte& info = undelivered_sdu_info_queue[pdcp_sn]; // Remove RLC SN from PDCP PDU undelivered list info.ack_segment(acked_segment); diff --git a/lib/src/rlc/rlc_am_lte_packing.cc b/lib/src/rlc/rlc_am_lte_packing.cc index 02643f3fc..3cff0dd13 100644 --- a/lib/src/rlc/rlc_am_lte_packing.cc +++ b/lib/src/rlc/rlc_am_lte_packing.cc @@ -276,7 +276,8 @@ bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status, uint32_t rx_win_ return true; } -void rlc_am_undelivered_sdu_info_to_string(fmt::memory_buffer& buffer, const std::vector& info_queue) +void rlc_am_undelivered_sdu_info_to_string(fmt::memory_buffer& buffer, + const std::vector >& info_queue) { fmt::format_to(buffer, "\n"); for (const auto& pdcp_pdu : info_queue) {