diff --git a/lib/include/srslte/common/common.h b/lib/include/srslte/common/common.h index 4b8c727b7..3ce6d5819 100644 --- a/lib/include/srslte/common/common.h +++ b/lib/include/srslte/common/common.h @@ -101,6 +101,10 @@ public: char debug_name[SRSLTE_BUFFER_POOL_LOG_NAME_LEN]; #endif + struct buffer_metadata_t { + uint32_t pdcp_sn; + } md; + byte_buffer_t() : N_bytes(0) { bzero(buffer, SRSLTE_MAX_BUFFER_SIZE_BYTES); @@ -116,6 +120,7 @@ public: msg = &buffer[SRSLTE_BUFFER_HEADER_OFFSET]; next = NULL; // copy actual contents + md = buf.md; N_bytes = buf.N_bytes; memcpy(msg, buf.msg, N_bytes); } @@ -128,6 +133,7 @@ public: msg = &buffer[SRSLTE_BUFFER_HEADER_OFFSET]; next = NULL; N_bytes = buf.N_bytes; + md = buf.md; memcpy(msg, buf.msg, N_bytes); return *this; } @@ -135,6 +141,7 @@ public: { msg = &buffer[SRSLTE_BUFFER_HEADER_OFFSET]; N_bytes = 0; + md = {}; #ifdef ENABLE_TIMESTAMP timestamp_is_set = false; #endif diff --git a/lib/include/srslte/interfaces/enb_interfaces.h b/lib/include/srslte/interfaces/enb_interfaces.h index cf3b84a27..c4dd8e335 100644 --- a/lib/include/srslte/interfaces/enb_interfaces.h +++ b/lib/include/srslte/interfaces/enb_interfaces.h @@ -387,7 +387,8 @@ class pdcp_interface_rlc { public: /* RLC calls PDCP to push a PDCP PDU. */ - virtual void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; + virtual void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0; + virtual void notify_delivery(uint16_t rnti, uint32_t lcid, const std::vector& pdcp_sns) = 0; }; // RRC interface for RLC diff --git a/lib/include/srslte/interfaces/gnb_interfaces.h b/lib/include/srslte/interfaces/gnb_interfaces.h index 04de849ed..150fadde2 100644 --- a/lib/include/srslte/interfaces/gnb_interfaces.h +++ b/lib/include/srslte/interfaces/gnb_interfaces.h @@ -82,8 +82,10 @@ class pdcp_interface_rlc_nr { public: /* RLC calls PDCP to push a PDCP PDU. */ - virtual void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; + virtual void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; + virtual void notify_delivery(uint16_t rnti, uint32_t lcid, const std::vector& tx_count) = 0; }; + class pdcp_interface_rrc_nr { public: @@ -96,6 +98,7 @@ public: virtual void enable_integrity(uint16_t rnti, uint32_t lcid) = 0; virtual void enable_encryption(uint16_t rnti, uint32_t lcid) = 0; }; + class pdcp_interface_sdap_nr { public: diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index 07fb695c9..d671a44cc 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -247,8 +247,8 @@ public: virtual uint32_t get_ipv4_addr() = 0; virtual bool get_ipv6_addr(uint8_t* ipv6_addr) = 0; virtual void - plmn_search_completed(const rrc_interface_nas::found_plmn_t found_plmns[rrc_interface_nas::MAX_FOUND_PLMNS], - int nof_plmns) = 0; + plmn_search_completed(const rrc_interface_nas::found_plmn_t found_plmns[rrc_interface_nas::MAX_FOUND_PLMNS], + int nof_plmns) = 0; virtual bool connection_request_completed(bool outcome) = 0; }; @@ -298,11 +298,12 @@ class pdcp_interface_rlc { public: /* RLC calls PDCP to push a PDCP PDU. */ - virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; - virtual void write_pdu_bcch_bch(srslte::unique_byte_buffer_t sdu) = 0; - virtual void write_pdu_bcch_dlsch(srslte::unique_byte_buffer_t sdu) = 0; - virtual void write_pdu_pcch(srslte::unique_byte_buffer_t sdu) = 0; - virtual void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; + virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; + virtual void write_pdu_bcch_bch(srslte::unique_byte_buffer_t sdu) = 0; + virtual void write_pdu_bcch_dlsch(srslte::unique_byte_buffer_t sdu) = 0; + virtual void write_pdu_pcch(srslte::unique_byte_buffer_t sdu) = 0; + virtual void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; + virtual void notify_delivery(uint32_t lcid, const std::vector& pdcp_sn) = 0; }; class pdcp_interface_gw @@ -630,8 +631,8 @@ public: } prach_info_t; virtual void - prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm, float ta_base_sec = 0.0f) = 0; - virtual prach_info_t prach_get_info() = 0; + prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm, float ta_base_sec = 0.0f) = 0; + virtual prach_info_t prach_get_info() = 0; /* Indicates the transmission of a SR signal in the next opportunity */ virtual void sr_send() = 0; diff --git a/lib/include/srslte/upper/pdcp.h b/lib/include/srslte/upper/pdcp.h index d4002f274..e823cca3e 100644 --- a/lib/include/srslte/upper/pdcp.h +++ b/lib/include/srslte/upper/pdcp.h @@ -56,6 +56,7 @@ public: void write_pdu_bcch_bch(unique_byte_buffer_t sdu) override; void write_pdu_bcch_dlsch(unique_byte_buffer_t sdu) override; void write_pdu_pcch(unique_byte_buffer_t sdu) override; + void notify_delivery(uint32_t lcid, const std::vector& pdcp_sn) override; // eNB-only methods std::map get_buffered_pdus(uint32_t lcid); diff --git a/lib/include/srslte/upper/pdcp_entity_base.h b/lib/include/srslte/upper/pdcp_entity_base.h index 312b1cef6..7785e014c 100644 --- a/lib/include/srslte/upper/pdcp_entity_base.h +++ b/lib/include/srslte/upper/pdcp_entity_base.h @@ -110,7 +110,8 @@ public: virtual void write_sdu(unique_byte_buffer_t sdu) = 0; // RLC interface - virtual void write_pdu(unique_byte_buffer_t pdu) = 0; + virtual void write_pdu(unique_byte_buffer_t pdu) = 0; + virtual void notify_delivery(const std::vector& tx_count) = 0; virtual void get_bearer_state(pdcp_lte_state_t* state) = 0; virtual void set_bearer_state(const pdcp_lte_state_t& state) = 0; diff --git a/lib/include/srslte/upper/pdcp_entity_lte.h b/lib/include/srslte/upper/pdcp_entity_lte.h index 44dfec476..35819a60c 100644 --- a/lib/include/srslte/upper/pdcp_entity_lte.h +++ b/lib/include/srslte/upper/pdcp_entity_lte.h @@ -53,6 +53,7 @@ public: // RLC interface void write_pdu(unique_byte_buffer_t pdu) override; + void notify_delivery(const std::vector& pdcp_sns) override; // Config helpers bool check_valid_config(); diff --git a/lib/include/srslte/upper/pdcp_entity_nr.h b/lib/include/srslte/upper/pdcp_entity_nr.h index bfe090487..7232d7209 100644 --- a/lib/include/srslte/upper/pdcp_entity_nr.h +++ b/lib/include/srslte/upper/pdcp_entity_nr.h @@ -49,6 +49,7 @@ public: // RLC interface void write_pdu(unique_byte_buffer_t pdu) final; + void notify_delivery(const std::vector& tx_count) final; // State variable setters (should be used only for testing) void set_tx_next(uint32_t tx_next_) { tx_next = tx_next_; } diff --git a/lib/include/srslte/upper/rlc_am_lte.h b/lib/include/srslte/upper/rlc_am_lte.h index 096ca41d4..a7c444917 100644 --- a/lib/include/srslte/upper/rlc_am_lte.h +++ b/lib/include/srslte/upper/rlc_am_lte.h @@ -40,10 +40,11 @@ struct rlc_amd_rx_pdu_segments_t { }; struct rlc_amd_tx_pdu_t { - rlc_amd_pdu_header_t header; - unique_byte_buffer_t buf; - uint32_t retx_count; - bool is_acked; + rlc_amd_pdu_header_t header; + unique_byte_buffer_t buf; + uint32_t retx_count; + bool is_acked; + std::array pdcp_tx_counts; }; struct rlc_amd_retx_t { @@ -53,6 +54,12 @@ struct rlc_amd_retx_t { uint32_t so_end; }; +struct pdcp_sdu_info_t { + uint32_t sn; + uint32_t acked_bytes; + uint32_t total_bytes; +}; + class rlc_am_lte : public rlc_common { public: @@ -145,7 +152,7 @@ private: // TX SDU buffers byte_buffer_queue tx_sdu_queue; - unique_byte_buffer_t tx_sdu; + unique_byte_buffer_t tx_sdu = nullptr; bool tx_enabled = false; @@ -174,6 +181,10 @@ private: srslte::timer_handler::unique_timer poll_retx_timer; srslte::timer_handler::unique_timer status_prohibit_timer; + // SDU info for PDCP notifications + uint32_t pdcp_info_queue_capacity = 128; + std::map undelivered_sdu_info_queue; + // Callback function for buffer status report bsr_callback_t bsr_callback; diff --git a/lib/include/srslte/upper/rlc_common.h b/lib/include/srslte/upper/rlc_common.h index 7fda6ccd5..dd721631f 100644 --- a/lib/include/srslte/upper/rlc_common.h +++ b/lib/include/srslte/upper/rlc_common.h @@ -256,9 +256,9 @@ public: virtual void reset_metrics() = 0; // PDCP interface - virtual void write_sdu(unique_byte_buffer_t sdu) = 0; - virtual void discard_sdu(uint32_t discard_sn) = 0; - virtual bool sdu_queue_is_full() = 0; + virtual void write_sdu(unique_byte_buffer_t sdu) = 0; + virtual void discard_sdu(uint32_t discard_sn) = 0; + virtual bool sdu_queue_is_full() = 0; // MAC interface virtual bool has_data() = 0; diff --git a/lib/src/upper/pdcp.cc b/lib/src/upper/pdcp.cc index 06d3282a9..fcdcf7543 100644 --- a/lib/src/upper/pdcp.cc +++ b/lib/src/upper/pdcp.cc @@ -282,6 +282,15 @@ void pdcp::write_pdu_mch(uint32_t lcid, unique_byte_buffer_t sdu) } } +void pdcp::notify_delivery(uint32_t lcid, const std::vector& pdcp_sns) +{ + if (valid_lcid(lcid)) { + pdcp_array.at(lcid)->notify_delivery(pdcp_sns); + } else { + pdcp_log->warning("Could not notify delivery: lcid=%d, nof_sn=%ld.\n", lcid, pdcp_sns.size()); + } +} + bool pdcp::valid_lcid(uint32_t lcid) { if (lcid >= SRSLTE_N_RADIO_BEARERS) { diff --git a/lib/src/upper/pdcp_entity_lte.cc b/lib/src/upper/pdcp_entity_lte.cc index f7a8a9b04..196b97b17 100644 --- a/lib/src/upper/pdcp_entity_lte.cc +++ b/lib/src/upper/pdcp_entity_lte.cc @@ -136,6 +136,9 @@ void pdcp_entity_lte::write_sdu(unique_byte_buffer_t sdu) srslte_direction_text[integrity_direction], srslte_direction_text[encryption_direction]); + // Set SDU metadata for RLC AM + sdu->md.pdcp_sn = st.next_pdcp_tx_sn; + // Increment NEXT_PDCP_TX_SN and TX_HFN st.next_pdcp_tx_sn++; if (st.next_pdcp_tx_sn > maximum_pdcp_sn) { @@ -302,7 +305,9 @@ void pdcp_entity_lte::handle_am_drb_pdu(srslte::unique_byte_buffer_t pdu) last_submit_diff_sn, reordering_window); return; // Discard - } else if ((int32_t)(st.next_pdcp_rx_sn - sn) > (int32_t)reordering_window) { + } + + if ((int32_t)(st.next_pdcp_rx_sn - sn) > (int32_t)reordering_window) { log->debug("(Next_PDCP_RX_SN - SN) is larger than re-ordering window.\n"); st.rx_hfn++; count = (st.rx_hfn << cfg.sn_len) | sn; @@ -334,6 +339,14 @@ void pdcp_entity_lte::handle_am_drb_pdu(srslte::unique_byte_buffer_t pdu) gw->write_pdu(lcid, std::move(pdu)); } +/**************************************************************************** + * Delivery notifications from RLC + ***************************************************************************/ +void pdcp_entity_lte::notify_delivery(const std::vector& pdcp_sns) +{ + log->debug("Received delivery notification from RLC. Number of PDU notified=%ld\n", pdcp_sns.size()); +} + /**************************************************************************** * Config checking helper ***************************************************************************/ diff --git a/lib/src/upper/pdcp_entity_nr.cc b/lib/src/upper/pdcp_entity_nr.cc index e3e33d1c6..ee0fedf79 100644 --- a/lib/src/upper/pdcp_entity_nr.cc +++ b/lib/src/upper/pdcp_entity_nr.cc @@ -106,12 +106,15 @@ void pdcp_entity_nr::write_sdu(unique_byte_buffer_t sdu) // Append MAC-I append_mac(sdu, mac); - // Increment TX_NEXT - tx_next++; + // Set meta-data for RLC AM + sdu->md.pdcp_sn = tx_next; // Check if PDCP is associated with more than on RLC entity TODO // Write to lower layers rlc->write_sdu(lcid, std::move(sdu)); + + // Increment TX_NEXT + tx_next++; } // RLC interface @@ -199,6 +202,12 @@ void pdcp_entity_nr::write_pdu(unique_byte_buffer_t pdu) } } +// Notification of delivery +void pdcp_entity_nr::notify_delivery(const std::vector& pdcp_sns) +{ + log->debug("Received delivery notification from RLC. Nof SNs=%ld\n", pdcp_sns.size()); +} + /* * Packing / Unpacking Helpers */ diff --git a/lib/src/upper/rlc_am_lte.cc b/lib/src/upper/rlc_am_lte.cc index ab50c750f..2a34ce32a 100644 --- a/lib/src/upper/rlc_am_lte.cc +++ b/lib/src/upper/rlc_am_lte.cc @@ -356,6 +356,12 @@ int rlc_am_lte::rlc_am_lte_tx::write_sdu(unique_byte_buffer_t sdu) return SRSLTE_ERROR; } + // Get SDU info + pdcp_sdu_info_t info = {}; + info.sn = sdu->md.pdcp_sn; + info.total_bytes = sdu->N_bytes; + + // Store SDU uint8_t* msg_ptr = sdu->msg; uint32_t nof_bytes = sdu->N_bytes; srslte::error_type ret = tx_sdu_queue.try_write(std::move(sdu)); @@ -373,6 +379,16 @@ int rlc_am_lte::rlc_am_lte_tx::write_sdu(unique_byte_buffer_t sdu) return SRSLTE_ERROR; } + // Store SDU info + uint32_t info_count = undelivered_sdu_info_queue.count(info.sn); + if (info_count != 0) { + log->error("PDCP SDU info alreay exists\n"); + return SRSLTE_ERROR; + } else if (info_count > pdcp_info_queue_capacity) { + log->error("PDCP SDU info exceeds maximum queue capacity\n"); + return SRSLTE_ERROR; + } + undelivered_sdu_info_queue[info.sn] = info; return SRSLTE_SUCCESS; } @@ -829,6 +845,9 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt log->debug("%s Building PDU - pdu_space: %d, head_len: %d \n", RB_NAME, pdu_space, head_len); + // Helper to keep track of the PDCP counts for each RLC PDU + std::array pdcp_tx_counts = {}; + // Check for SDU segment if (tx_sdu != NULL) { to_move = ((pdu_space - head_len) >= tx_sdu->N_bytes) ? tx_sdu->N_bytes : pdu_space - head_len; @@ -838,6 +857,7 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt pdu->N_bytes += to_move; tx_sdu->N_bytes -= to_move; tx_sdu->msg += to_move; + pdcp_tx_counts[0] = tx_sdu->md.pdcp_sn; if (tx_sdu->N_bytes == 0) { log->debug("%s Complete SDU scheduled for tx.\n", RB_NAME); tx_sdu.reset(); @@ -877,6 +897,7 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt pdu->N_bytes += to_move; tx_sdu->N_bytes -= to_move; tx_sdu->msg += to_move; + pdcp_tx_counts[header.N_li] = tx_sdu->md.pdcp_sn; if (tx_sdu->N_bytes == 0) { log->debug("%s Complete SDU scheduled for tx.\n", RB_NAME); tx_sdu.reset(); @@ -925,11 +946,12 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt vt_s = (vt_s + 1) % MOD; // Place PDU in tx_window, write header and TX - tx_window[header.sn].buf = std::move(pdu); - tx_window[header.sn].header = header; - tx_window[header.sn].is_acked = false; - tx_window[header.sn].retx_count = 0; - const byte_buffer_t* buffer_ptr = tx_window[header.sn].buf.get(); + tx_window[header.sn].buf = std::move(pdu); + tx_window[header.sn].header = header; + tx_window[header.sn].is_acked = false; + tx_window[header.sn].retx_count = 0; + tx_window[header.sn].pdcp_tx_counts = pdcp_tx_counts; + const byte_buffer_t* buffer_ptr = tx_window[header.sn].buf.get(); uint8_t* ptr = payload; rlc_am_write_data_pdu_header(&header, &ptr); @@ -967,8 +989,9 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no // Handle ACKs and NACKs std::map::iterator it; - bool update_vt_a = true; - uint32_t i = vt_a; + bool update_vt_a = true; + uint32_t i = vt_a; + std::vector notify_info_vec = {}; while (TX_MOD_BASE(i) < TX_MOD_BASE(status.ack_sn) && TX_MOD_BASE(i) < TX_MOD_BASE(vt_s)) { bool nack = false; @@ -1027,6 +1050,28 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no it = tx_window.find(i); if (it != tx_window.end()) { if (update_vt_a) { + // Notify PDCP of the number of bytes succesfully delivered + uint32_t notified_bytes = 0; + uint32_t nof_bytes = 0; + uint32_t pdcp_sn = 0; + for (uint32_t pdcp_notify_it = 0; pdcp_notify_it < it->second.header.N_li; pdcp_notify_it++) { + nof_bytes = it->second.header.li[pdcp_notify_it]; + pdcp_sn = it->second.pdcp_tx_counts[pdcp_notify_it]; + undelivered_sdu_info_queue[pdcp_sn].acked_bytes += nof_bytes; + if (undelivered_sdu_info_queue[pdcp_sn].acked_bytes >= undelivered_sdu_info_queue[pdcp_sn].total_bytes) { + undelivered_sdu_info_queue.erase(pdcp_sn); + notify_info_vec.push_back(pdcp_sn); + log->debug("Reporting to PDCP: TX COUNT=%d, nof_bytes=%d\n", pdcp_sn, nof_bytes); + } + } + pdcp_sn = it->second.pdcp_tx_counts[it->second.header.N_li]; + nof_bytes = it->second.buf->N_bytes - notified_bytes; // Notify last SDU + undelivered_sdu_info_queue[pdcp_sn].acked_bytes += nof_bytes; + if (undelivered_sdu_info_queue[pdcp_sn].acked_bytes >= undelivered_sdu_info_queue[pdcp_sn].total_bytes) { + undelivered_sdu_info_queue.erase(pdcp_sn); + notify_info_vec.push_back(pdcp_sn); + log->debug("Reporting to PDCP: TX COUNT=%d, nof_bytes=%d\n", pdcp_sn, nof_bytes); + } tx_window.erase(it); vt_a = (vt_a + 1) % MOD; vt_ms = (vt_ms + 1) % MOD; @@ -1037,6 +1082,10 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no i = (i + 1) % MOD; } + if (not notify_info_vec.empty()) { + parent->pdcp->notify_delivery(parent->lcid, notify_info_vec); + } + debug_state(); pthread_mutex_unlock(&mutex); diff --git a/lib/test/upper/CMakeLists.txt b/lib/test/upper/CMakeLists.txt index f70da8aba..d5ccb8028 100644 --- a/lib/test/upper/CMakeLists.txt +++ b/lib/test/upper/CMakeLists.txt @@ -18,6 +18,10 @@ add_executable(rlc_am_test rlc_am_test.cc) target_link_libraries(rlc_am_test srslte_upper srslte_phy srslte_common) add_test(rlc_am_test rlc_am_test) +add_executable(rlc_am_notify_pdcp_test rlc_am_notify_pdcp_test.cc) +target_link_libraries(rlc_am_notify_pdcp_test srslte_upper srslte_phy) +add_test(rlc_am_notify_pdcp_test rlc_am_notify_pdcp_test) + if (ENABLE_5GNR) add_executable(rlc_am_nr_pdu_test rlc_am_nr_pdu_test.cc) target_link_libraries(rlc_am_nr_pdu_test srslte_upper srslte_phy) diff --git a/lib/test/upper/rlc_am_notify_pdcp_test.cc b/lib/test/upper/rlc_am_notify_pdcp_test.cc new file mode 100644 index 000000000..519583ec3 --- /dev/null +++ b/lib/test/upper/rlc_am_notify_pdcp_test.cc @@ -0,0 +1,516 @@ +/* + * Copyright 2013-2020 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include "srslte/common/test_common.h" +#include "srslte/upper/rlc_am_lte.h" +#include + +srslte::log_ref rlc_log("RLC"); + +class pdcp_tester : public srsue::pdcp_interface_rlc +{ +public: + std::map notified_counts; // Map of PDCP Tx count to acknoledged bytes + // PDCP interface + void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu) {} + void write_pdu_bcch_bch(srslte::unique_byte_buffer_t sdu) {} + void write_pdu_bcch_dlsch(srslte::unique_byte_buffer_t sdu) {} + void write_pdu_pcch(srslte::unique_byte_buffer_t sdu) {} + void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t pdu) {} + void notify_delivery(uint32_t lcid, const std::vector& pdcp_sn_vec) + { + for (uint32_t pdcp_sn : pdcp_sn_vec) { + if (notified_counts.find(pdcp_sn) == notified_counts.end()) { + notified_counts[pdcp_sn] = 0; + } + assert(lcid == 1); + notified_counts[pdcp_sn] += 1; + // std::cout << "Notified " << notified_counts[tx_count] << "Tx count" << tx_count << "nof_bytes" << nof_bytes + // << std::endl; + } + } +}; + +class rrc_tester : public srsue::rrc_interface_rlc +{ + void max_retx_attempted() {} + std::string get_rb_name(uint32_t lcid) { return "DRB1"; } + void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) {} +}; + +// Simple test of a single TX PDU and an imediate ACK +int simple_sdu_notify_test() +{ + + srslte::byte_buffer_pool* pool = srslte::byte_buffer_pool::get_instance(); + pdcp_tester pdcp; + rrc_tester rrc; + srslte::timer_handler timers(8); + srslte::rlc_am_lte rlc(rlc_log, 1, &pdcp, &rrc, &timers); + + uint8_t sdu[] = {0x22, 0x40}; + uint32_t SDU_LEN = 2; + + srslte::unique_byte_buffer_t sdu_buf = allocate_unique_buffer(*pool); + srslte::unique_byte_buffer_t pdu_buf = allocate_unique_buffer(*pool); + srslte::unique_byte_buffer_t sta_buf = allocate_unique_buffer(*pool); + + if (not rlc.configure(srslte::rlc_config_t::default_rlc_am_config())) { + return -1; + } + + // Write SDU into RLC entity + memcpy(sdu_buf->msg, &sdu[0], SDU_LEN); + sdu_buf->N_bytes = SDU_LEN; + sdu_buf->md.pdcp_sn = 10; + rlc.write_sdu(std::move(sdu_buf)); + + TESTASSERT(4 == rlc.get_buffer_state()); // 2 bytes for header + 2 bytes for payload + + // Read 1 PDUs from RLC1 (4 bytes) + uint32_t len = rlc.read_pdu(pdu_buf->msg, 4); + pdu_buf->N_bytes = len; + TESTASSERT(0 == rlc.get_buffer_state()); + + // Feed ack to PDU + srslte::rlc_status_pdu_t s1; + s1.ack_sn = 1; + s1.N_nack = 0; + + sta_buf->N_bytes = srslte::rlc_am_write_status_pdu(&s1, sta_buf->msg); + rlc.write_pdu(sta_buf->msg, sta_buf->N_bytes); + + // Check PDCP notifications + TESTASSERT(pdcp.notified_counts.size() == 1); + TESTASSERT(pdcp.notified_counts.find(10) != pdcp.notified_counts.end()); + TESTASSERT(pdcp.notified_counts[10] == 1); + + return SRSLTE_SUCCESS; +} + +// Test of a single SDU transmitted over 2 PDUs. +// Both PDUs are ACKed in the same status PDU. +int two_pdus_notify_test() +{ + + srslte::byte_buffer_pool* pool = srslte::byte_buffer_pool::get_instance(); + pdcp_tester pdcp; + rrc_tester rrc; + srslte::timer_handler timers(8); + srslte::rlc_am_lte rlc(rlc_log, 1, &pdcp, &rrc, &timers); + + uint8_t sdu[] = {0x22, 0x40, 0x30, 0x21, 0x50}; + uint32_t SDU_LEN = 5; + + srslte::unique_byte_buffer_t sdu_buf = allocate_unique_buffer(*pool); + srslte::unique_byte_buffer_t pdu1_buf = allocate_unique_buffer(*pool); + srslte::unique_byte_buffer_t pdu2_buf = allocate_unique_buffer(*pool); + srslte::unique_byte_buffer_t sta_buf = allocate_unique_buffer(*pool); + + if (not rlc.configure(srslte::rlc_config_t::default_rlc_am_config())) { + return -1; + } + + // Write SDU into RLC entity + memcpy(sdu_buf->msg, &sdu[0], SDU_LEN); + sdu_buf->N_bytes = SDU_LEN; + sdu_buf->md.pdcp_sn = 10; + rlc.write_sdu(std::move(sdu_buf)); + + TESTASSERT(7 == rlc.get_buffer_state()); // 2 bytes for header + 5 for payload + + // Read first PDU from RLC1 (3 bytes of data) + pdu1_buf->N_bytes = rlc.read_pdu(pdu1_buf->msg, 5); // Read + TESTASSERT(4 == rlc.get_buffer_state()); // 2 bytes for header + 2 for payload + + // Read second PDUs from RLC1 (3 bytes of data) + pdu2_buf->N_bytes = rlc.read_pdu(pdu2_buf->msg, 4); // 2 bytes for header + 2 for payload + TESTASSERT(0 == rlc.get_buffer_state()); + + // Feed ack of PDU1 to RLC + srslte::rlc_status_pdu_t s1; + s1.ack_sn = 1; + s1.N_nack = 0; + + sta_buf->N_bytes = srslte::rlc_am_write_status_pdu(&s1, sta_buf->msg); + rlc.write_pdu(sta_buf->msg, sta_buf->N_bytes); + + // Feed ack of PDU2 to RLC + srslte::rlc_status_pdu_t s2; + s2.ack_sn = 2; + s2.N_nack = 0; + + sta_buf->N_bytes = srslte::rlc_am_write_status_pdu(&s2, sta_buf->msg); + rlc.write_pdu(sta_buf->msg, sta_buf->N_bytes); + + // Check PDCP notifications + TESTASSERT(pdcp.notified_counts.size() == 1); + TESTASSERT(pdcp.notified_counts.find(10) != pdcp.notified_counts.end()); + TESTASSERT(pdcp.notified_counts[10] == 1); + + return SRSLTE_SUCCESS; +} + +// Test of a two SDUs transmitted over a single PDU. +// Two SDUs -> K=1 (even number of LIs) +// The PDU is ACKed imediatly. +int two_sdus_notify_test() +{ + + srslte::byte_buffer_pool* pool = srslte::byte_buffer_pool::get_instance(); + pdcp_tester pdcp; + rrc_tester rrc; + srslte::timer_handler timers(8); + srslte::rlc_am_lte rlc(rlc_log, 1, &pdcp, &rrc, &timers); + + uint8_t sdu1[] = {0x22, 0x40, 0x30, 0x21, 0x50}; + uint32_t SDU1_LEN = 5; + + uint8_t sdu2[] = {0x22, 0x40}; + uint32_t SDU2_LEN = 2; + srslte::unique_byte_buffer_t sdu1_buf = allocate_unique_buffer(*pool); + srslte::unique_byte_buffer_t sdu2_buf = allocate_unique_buffer(*pool); + srslte::unique_byte_buffer_t pdu_buf = allocate_unique_buffer(*pool); + srslte::unique_byte_buffer_t sta_buf = allocate_unique_buffer(*pool); + + if (not rlc.configure(srslte::rlc_config_t::default_rlc_am_config())) { + return -1; + } + + // Write SDU into RLC entity + memcpy(sdu1_buf->msg, &sdu1[0], SDU1_LEN); + sdu1_buf->N_bytes = SDU1_LEN; + sdu1_buf->md.pdcp_sn = 10; + rlc.write_sdu(std::move(sdu1_buf)); + TESTASSERT(7 == rlc.get_buffer_state()); + + memcpy(sdu2_buf->msg, &sdu2[0], SDU2_LEN); + sdu2_buf->N_bytes = SDU2_LEN; + sdu2_buf->md.pdcp_sn = 13; + rlc.write_sdu(std::move(sdu2_buf)); + TESTASSERT(11 == rlc.get_buffer_state()); // 2 bytes for header, 2 bytes for Li, and 7 for data + + // Read PDU from RLC1 (7 bytes of data) + pdu_buf->N_bytes = rlc.read_pdu(pdu_buf->msg, 11); // 2 bytes for fixed header + 2 bytes for one LI + // + 7 bytes for payload + + TESTASSERT(0 == rlc.get_buffer_state()); + + // Feed ack of PDU1 to RLC + srslte::rlc_status_pdu_t s1; + s1.ack_sn = 1; + s1.N_nack = 0; + + sta_buf->N_bytes = srslte::rlc_am_write_status_pdu(&s1, sta_buf->msg); + rlc.write_pdu(sta_buf->msg, sta_buf->N_bytes); + + // Check PDCP notifications + TESTASSERT(pdcp.notified_counts.size() == 2); + TESTASSERT(pdcp.notified_counts.find(10) != pdcp.notified_counts.end()); + TESTASSERT(pdcp.notified_counts[10] == 1); + TESTASSERT(pdcp.notified_counts.find(13) != pdcp.notified_counts.end()); + TESTASSERT(pdcp.notified_counts[13] == 1); + + return SRSLTE_SUCCESS; +} + +// Test of a three SDUs transmitted over a single PDU. +// The PDU is ACKed imediatly. +int three_sdus_notify_test() +{ + + srslte::byte_buffer_pool* pool = srslte::byte_buffer_pool::get_instance(); + pdcp_tester pdcp; + rrc_tester rrc; + srslte::timer_handler timers(8); + srslte::rlc_am_lte rlc(rlc_log, 1, &pdcp, &rrc, &timers); + + uint8_t sdu1[] = {0x22, 0x40, 0x30, 0x21, 0x50}; + uint32_t SDU1_LEN = 5; + + uint8_t sdu2[] = {0x22, 0x40}; + uint32_t SDU2_LEN = 2; + + uint8_t sdu3[] = {0x22, 0x40, 0x00}; + uint32_t SDU3_LEN = 3; + + srslte::unique_byte_buffer_t sdu1_buf = allocate_unique_buffer(*pool); + srslte::unique_byte_buffer_t sdu2_buf = allocate_unique_buffer(*pool); + srslte::unique_byte_buffer_t sdu3_buf = allocate_unique_buffer(*pool); + srslte::unique_byte_buffer_t pdu_buf = allocate_unique_buffer(*pool); + srslte::unique_byte_buffer_t sta_buf = allocate_unique_buffer(*pool); + + if (not rlc.configure(srslte::rlc_config_t::default_rlc_am_config())) { + return -1; + } + + // Write SDU into RLC entity + memcpy(sdu1_buf->msg, &sdu1[0], SDU1_LEN); + sdu1_buf->N_bytes = SDU1_LEN; + sdu1_buf->md.pdcp_sn = 10; + rlc.write_sdu(std::move(sdu1_buf)); + TESTASSERT(7 == rlc.get_buffer_state()); + + memcpy(sdu2_buf->msg, &sdu2[0], SDU2_LEN); + sdu2_buf->N_bytes = SDU2_LEN; + sdu2_buf->md.pdcp_sn = 13; + rlc.write_sdu(std::move(sdu2_buf)); + + memcpy(sdu3_buf->msg, &sdu3[0], SDU3_LEN); + sdu3_buf->N_bytes = SDU3_LEN; + sdu3_buf->md.pdcp_sn = 14; + rlc.write_sdu(std::move(sdu3_buf)); + + TESTASSERT(15 == rlc.get_buffer_state()); // 2 bytes for fixed header, 3 bytes for two LIs, 10 for data + + // Read PDU from RLC1 (10 bytes of data) + pdu_buf->N_bytes = rlc.read_pdu(pdu_buf->msg, 15); // 2 bytes for fixed header + 5 bytes for three LIs + // + 10 bytes for payload + + TESTASSERT(0 == rlc.get_buffer_state()); + + // Feed ack of PDU1 to RLC + srslte::rlc_status_pdu_t s1; + s1.ack_sn = 1; + s1.N_nack = 0; + + sta_buf->N_bytes = srslte::rlc_am_write_status_pdu(&s1, sta_buf->msg); + rlc.write_pdu(sta_buf->msg, sta_buf->N_bytes); + + // Check PDCP notifications + TESTASSERT(pdcp.notified_counts.size() == 3); + TESTASSERT(pdcp.notified_counts.find(10) != pdcp.notified_counts.end()); + TESTASSERT(pdcp.notified_counts.find(13) != pdcp.notified_counts.end()); + TESTASSERT(pdcp.notified_counts.find(14) != pdcp.notified_counts.end()); + TESTASSERT(pdcp.notified_counts[10] == 1); + TESTASSERT(pdcp.notified_counts[13] == 1); + TESTASSERT(pdcp.notified_counts[14] == 1); + + return SRSLTE_SUCCESS; +} +// Test notification of an RTXED SDU. +int rtxed_sdu_notify_test() +{ + + srslte::byte_buffer_pool* pool = srslte::byte_buffer_pool::get_instance(); + pdcp_tester pdcp; + rrc_tester rrc; + srslte::timer_handler timers(8); + srslte::rlc_am_lte rlc(rlc_log, 1, &pdcp, &rrc, &timers); + + uint8_t sdu[] = {0x22, 0x40, 0x30, 0x21, 0x50}; + uint32_t SDU_LEN = 5; + + srslte::unique_byte_buffer_t sdu_buf = allocate_unique_buffer(*pool); + srslte::unique_byte_buffer_t pdu_buf = allocate_unique_buffer(*pool); + srslte::unique_byte_buffer_t sta_buf = allocate_unique_buffer(*pool); + + if (not rlc.configure(srslte::rlc_config_t::default_rlc_am_config())) { + return -1; + } + + // Write SDU into RLC entity + memcpy(sdu_buf->msg, &sdu[0], SDU_LEN); + sdu_buf->N_bytes = SDU_LEN; + sdu_buf->md.pdcp_sn = 10; + rlc.write_sdu(std::move(sdu_buf)); + TESTASSERT(7 == rlc.get_buffer_state()); + + // Read first PDU from RLC (5 bytes of data) + pdu_buf->N_bytes = rlc.read_pdu(pdu_buf->msg, 7); // 2 bytes for fixed header + 5 bytes for payload + TESTASSERT(0 == rlc.get_buffer_state()); + + // Feed Nack of PDU1 to RLC + srslte::rlc_status_pdu_t s1; + s1.ack_sn = 1; + s1.N_nack = 1; + s1.nacks[0].nack_sn = 0; + + sta_buf->N_bytes = srslte::rlc_am_write_status_pdu(&s1, sta_buf->msg); + rlc.write_pdu(sta_buf->msg, sta_buf->N_bytes); + TESTASSERT(7 == rlc.get_buffer_state()); + + // Check PDCP notifications + TESTASSERT(pdcp.notified_counts.empty()); + + // Read rtxed PDU from RLC (5 bytes of data) + pdu_buf->N_bytes = rlc.read_pdu(pdu_buf->msg, 7); // 2 bytes for fixed header + 5 bytes for payload + TESTASSERT(0 == rlc.get_buffer_state()); + + // Feed ack of PDU1 to RLC + srslte::rlc_status_pdu_t s2; + s2.ack_sn = 1; + s2.N_nack = 0; + sta_buf->N_bytes = srslte::rlc_am_write_status_pdu(&s2, sta_buf->msg); + rlc.write_pdu(sta_buf->msg, sta_buf->N_bytes); + TESTASSERT(0 == rlc.get_buffer_state()); + + // Check PDCP notifications + TESTASSERT(pdcp.notified_counts.size() == 1); + TESTASSERT(pdcp.notified_counts.find(10) != pdcp.notified_counts.end()); + TESTASSERT(pdcp.notified_counts[10] == 1); + + return SRSLTE_SUCCESS; +} + +// Test out of order ACK for SDU. +// Two sdus are transmitted, and ack arrives out of order +int two_sdus_out_of_order_ack_notify_test() +{ + srslte::byte_buffer_pool* pool = srslte::byte_buffer_pool::get_instance(); + pdcp_tester pdcp; + rrc_tester rrc; + srslte::timer_handler timers(8); + srslte::rlc_am_lte rlc(rlc_log, 1, &pdcp, &rrc, &timers); + + uint8_t sdu[] = {0x22, 0x40, 0x30, 0x21, 0x50}; + uint32_t SDU_LEN = 5; + + srslte::unique_byte_buffer_t sdu_buf = allocate_unique_buffer(*pool); + srslte::unique_byte_buffer_t pdu1_buf = allocate_unique_buffer(*pool); + srslte::unique_byte_buffer_t pdu2_buf = allocate_unique_buffer(*pool); + srslte::unique_byte_buffer_t sta_buf = allocate_unique_buffer(*pool); + + if (not rlc.configure(srslte::rlc_config_t::default_rlc_am_config())) { + return -1; + } + + // Write SDU into RLC entity + memcpy(sdu_buf->msg, &sdu[0], SDU_LEN); + sdu_buf->N_bytes = SDU_LEN; + sdu_buf->md.pdcp_sn = 10; + rlc.write_sdu(std::move(sdu_buf)); + + TESTASSERT(7 == rlc.get_buffer_state()); // 2 bytes for header + 5 for payload + + // Read first PDU from RLC1 (3 bytes of data) + pdu1_buf->N_bytes = rlc.read_pdu(pdu1_buf->msg, 5); // Read + TESTASSERT(4 == rlc.get_buffer_state()); // 2 bytes for header + 2 for payload + + // Read second PDUs from RLC1 (3 bytes of data) + pdu2_buf->N_bytes = rlc.read_pdu(pdu2_buf->msg, 4); // 2 bytes for header + 2 for payload + TESTASSERT(0 == rlc.get_buffer_state()); + + // Feed ack of PDU1 to RLC + srslte::rlc_status_pdu_t s1; + s1.ack_sn = 1; + s1.N_nack = 0; + + // Intentionally do not write first ack to RLC + + // Feed ack of PDU2 to RLC + srslte::rlc_status_pdu_t s2; + s2.ack_sn = 2; + s2.N_nack = 0; + + // Write second ack + sta_buf->N_bytes = srslte::rlc_am_write_status_pdu(&s2, sta_buf->msg); + rlc.write_pdu(sta_buf->msg, sta_buf->N_bytes); + + // Check PDCP notifications + TESTASSERT(pdcp.notified_counts.size() == 1); + TESTASSERT(pdcp.notified_counts.find(10) != pdcp.notified_counts.end()); + TESTASSERT(pdcp.notified_counts[10] == 1); + + // Write first ack (out of order) + sta_buf->N_bytes = srslte::rlc_am_write_status_pdu(&s1, sta_buf->msg); + rlc.write_pdu(sta_buf->msg, sta_buf->N_bytes); + + // Check PDCP notifications + TESTASSERT(pdcp.notified_counts.size() == 1); + TESTASSERT(pdcp.notified_counts.find(10) != pdcp.notified_counts.end()); + TESTASSERT(pdcp.notified_counts[10] == 1); + return SRSLTE_SUCCESS; +} + +// Test out-of-order ack of a single SDU transmitted over 2 PDUs. +int two_pdus_out_of_order_ack_notify_test() +{ + + srslte::byte_buffer_pool* pool = srslte::byte_buffer_pool::get_instance(); + pdcp_tester pdcp; + rrc_tester rrc; + srslte::timer_handler timers(8); + srslte::rlc_am_lte rlc(rlc_log, 1, &pdcp, &rrc, &timers); + + uint8_t sdu[] = {0x22, 0x40, 0x30, 0x21, 0x50}; + uint32_t SDU_LEN = 5; + + srslte::unique_byte_buffer_t sdu_buf = allocate_unique_buffer(*pool); + srslte::unique_byte_buffer_t pdu1_buf = allocate_unique_buffer(*pool); + srslte::unique_byte_buffer_t pdu2_buf = allocate_unique_buffer(*pool); + srslte::unique_byte_buffer_t sta_buf = allocate_unique_buffer(*pool); + + if (not rlc.configure(srslte::rlc_config_t::default_rlc_am_config())) { + return -1; + } + + // Write SDU into RLC entity + memcpy(sdu_buf->msg, &sdu[0], SDU_LEN); + sdu_buf->N_bytes = SDU_LEN; + sdu_buf->md.pdcp_sn = 10; + rlc.write_sdu(std::move(sdu_buf)); + + TESTASSERT(7 == rlc.get_buffer_state()); // 2 bytes for header + 5 for payload + + // Read first PDU from RLC1 (3 bytes of data) + pdu1_buf->N_bytes = rlc.read_pdu(pdu1_buf->msg, 5); // Read + TESTASSERT(4 == rlc.get_buffer_state()); // 2 bytes for header + 2 for payload + + // Read second PDUs from RLC1 (3 bytes of data) + pdu2_buf->N_bytes = rlc.read_pdu(pdu2_buf->msg, 4); // 2 bytes for header + 2 for payload + TESTASSERT(0 == rlc.get_buffer_state()); + + // Feed ack of PDU1 to RLC + srslte::rlc_status_pdu_t s1; + s1.ack_sn = 1; + s1.N_nack = 0; + + sta_buf->N_bytes = srslte::rlc_am_write_status_pdu(&s1, sta_buf->msg); + rlc.write_pdu(sta_buf->msg, sta_buf->N_bytes); + + // Feed ack of PDU2 to RLC + srslte::rlc_status_pdu_t s2; + s2.ack_sn = 2; + s2.N_nack = 0; + + sta_buf->N_bytes = srslte::rlc_am_write_status_pdu(&s2, sta_buf->msg); + rlc.write_pdu(sta_buf->msg, sta_buf->N_bytes); + + // Check PDCP notifications + TESTASSERT(pdcp.notified_counts.size() == 1); + TESTASSERT(pdcp.notified_counts.find(10) != pdcp.notified_counts.end()); + TESTASSERT(pdcp.notified_counts[10] == 1); + + return SRSLTE_SUCCESS; +} +int main(int argc, char** argv) +{ + srslte::byte_buffer_pool::get_instance(); + TESTASSERT(simple_sdu_notify_test() == SRSLTE_SUCCESS); + TESTASSERT(two_pdus_notify_test() == SRSLTE_SUCCESS); + TESTASSERT(two_sdus_notify_test() == SRSLTE_SUCCESS); + TESTASSERT(three_sdus_notify_test() == SRSLTE_SUCCESS); + TESTASSERT(rtxed_sdu_notify_test() == SRSLTE_SUCCESS); + TESTASSERT(two_sdus_out_of_order_ack_notify_test() == SRSLTE_SUCCESS); + srslte::byte_buffer_pool::cleanup(); + return SRSLTE_SUCCESS; +} diff --git a/lib/test/upper/rlc_am_test.cc b/lib/test/upper/rlc_am_test.cc index 2b7c3c560..aa8aeecc5 100644 --- a/lib/test/upper/rlc_am_test.cc +++ b/lib/test/upper/rlc_am_test.cc @@ -57,6 +57,7 @@ public: void write_pdu_bcch_dlsch(unique_byte_buffer_t sdu) {} void write_pdu_pcch(unique_byte_buffer_t sdu) {} void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t pdu) {} + void notify_delivery(uint32_t lcid, const std::vector& tx_count) {} // RRC interface void max_retx_attempted() {} diff --git a/lib/test/upper/rlc_common_test.cc b/lib/test/upper/rlc_common_test.cc index 19bc3bd45..308ecc2f6 100644 --- a/lib/test/upper/rlc_common_test.cc +++ b/lib/test/upper/rlc_common_test.cc @@ -46,6 +46,7 @@ public: } sdus[n_sdus++] = std::move(sdu); } + void notify_delivery(uint32_t lcid, const std::vector& pdcp_sn) {} void write_pdu_bcch_bch(unique_byte_buffer_t sdu) {} void write_pdu_bcch_dlsch(unique_byte_buffer_t sdu) {} void write_pdu_pcch(unique_byte_buffer_t sdu) {} diff --git a/lib/test/upper/rlc_stress_test.cc b/lib/test/upper/rlc_stress_test.cc index 324f126f8..2393b1e8f 100644 --- a/lib/test/upper/rlc_stress_test.cc +++ b/lib/test/upper/rlc_stress_test.cc @@ -308,21 +308,14 @@ private: std::mt19937 mt19937; std::uniform_real_distribution real_dist; - byte_buffer_pool* pool = nullptr; + byte_buffer_pool* pool = nullptr; }; class rlc_tester : public pdcp_interface_rlc, public rrc_interface_rlc, public thread { public: rlc_tester(rlc_interface_pdcp* rlc_, std::string name_, stress_test_args_t args_, uint32_t lcid_) : - log("TEST"), - rlc(rlc_), - run_enable(true), - rx_pdus(), - name(name_), - args(args_), - lcid(lcid_), - thread("RLC_TESTER") + log("TEST"), rlc(rlc_), run_enable(true), rx_pdus(), name(name_), args(args_), lcid(lcid_), thread("RLC_TESTER") { log.set_level(srslte::LOG_LEVEL_ERROR); log.set_hex_limit(LOG_HEX_LIMIT); @@ -351,6 +344,7 @@ public: void write_pdu_bcch_dlsch(unique_byte_buffer_t sdu) {} void write_pdu_pcch(unique_byte_buffer_t sdu) {} void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t sdu) {} + void notify_delivery(uint32_t lcid, const std::vector& pdcp_sns) {} // RRC interface void max_retx_attempted() {} diff --git a/lib/test/upper/rlc_test_common.h b/lib/test/upper/rlc_test_common.h index f54d459b0..02c6baf75 100644 --- a/lib/test/upper/rlc_test_common.h +++ b/lib/test/upper/rlc_test_common.h @@ -49,6 +49,7 @@ public: void write_pdu_bcch_dlsch(unique_byte_buffer_t sdu) {} void write_pdu_pcch(unique_byte_buffer_t sdu) {} void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t sdu) { sdus.push_back(std::move(sdu)); } + void notify_delivery(uint32_t lcid, const std::vector& pdcp_sns) {} // RRC interface void max_retx_attempted() {} diff --git a/srsenb/hdr/stack/gnb_stack_nr.h b/srsenb/hdr/stack/gnb_stack_nr.h index fdeec4089..988546da7 100644 --- a/srsenb/hdr/stack/gnb_stack_nr.h +++ b/srsenb/hdr/stack/gnb_stack_nr.h @@ -57,8 +57,8 @@ public: bool get_metrics(srsenb::stack_metrics_t* metrics) final; // GW srsue stack_interface_gw dummy interface - bool is_registered(){return true;}; - bool start_service_request(){return true;}; + bool is_registered() { return true; }; + bool start_service_request() { return true; }; // PHY->MAC interface int sf_indication(const uint32_t tti); diff --git a/srsenb/hdr/stack/upper/pdcp.h b/srsenb/hdr/stack/upper/pdcp.h index c8ac96f3c..92c7e8b56 100644 --- a/srsenb/hdr/stack/upper/pdcp.h +++ b/srsenb/hdr/stack/upper/pdcp.h @@ -32,6 +32,7 @@ public: // pdcp_interface_rlc void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) override; + void notify_delivery(uint16_t rnti, uint32_t lcid, const std::vector& pdcp_sn) override; void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t sdu) {} // pdcp_interface_rrc diff --git a/srsenb/hdr/stack/upper/pdcp_nr.h b/srsenb/hdr/stack/upper/pdcp_nr.h index 75ed74ba0..6a25d00fe 100644 --- a/srsenb/hdr/stack/upper/pdcp_nr.h +++ b/srsenb/hdr/stack/upper/pdcp_nr.h @@ -40,6 +40,7 @@ public: // pdcp_interface_rlc_nr void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu); + void notify_delivery(uint16_t rnti, uint32_t lcid, const std::vector& tx_count); void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t sdu) {} // pdcp_interface_rrc_nr @@ -113,4 +114,4 @@ private: } // namespace srsenb -#endif // SRSENB_PDCP_NR_H \ No newline at end of file +#endif // SRSENB_PDCP_NR_H diff --git a/srsenb/hdr/stack/upper/rlc.h b/srsenb/hdr/stack/upper/rlc.h index fc91db4ce..79fe1337c 100644 --- a/srsenb/hdr/stack/upper/rlc.h +++ b/srsenb/hdr/stack/upper/rlc.h @@ -67,6 +67,7 @@ private: { public: void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu); + void notify_delivery(uint32_t lcid, const std::vector& tx_count); void write_pdu_bcch_bch(srslte::unique_byte_buffer_t sdu); void write_pdu_bcch_dlsch(srslte::unique_byte_buffer_t sdu); void write_pdu_pcch(srslte::unique_byte_buffer_t sdu); diff --git a/srsenb/hdr/stack/upper/rlc_nr.h b/srsenb/hdr/stack/upper/rlc_nr.h index 359fb5b8c..8089f0b4e 100644 --- a/srsenb/hdr/stack/upper/rlc_nr.h +++ b/srsenb/hdr/stack/upper/rlc_nr.h @@ -63,6 +63,7 @@ private: { public: void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu); + void notify_delivery(uint32_t lcid, const std::vector& pdcp_sns); void write_pdu_bcch_bch(srslte::unique_byte_buffer_t sdu); void write_pdu_bcch_dlsch(srslte::unique_byte_buffer_t sdu); void write_pdu_pcch(srslte::unique_byte_buffer_t sdu); @@ -92,4 +93,4 @@ private: } // namespace srsenb -#endif // SRSENB_RLC_NR_H \ No newline at end of file +#endif // SRSENB_RLC_NR_H diff --git a/srsenb/src/stack/rrc/rrc_nr.cc b/srsenb/src/stack/rrc/rrc_nr.cc index 916060561..f09a4791e 100644 --- a/srsenb/src/stack/rrc/rrc_nr.cc +++ b/srsenb/src/stack/rrc/rrc_nr.cc @@ -20,9 +20,7 @@ using namespace asn1::rrc_nr; namespace srsenb { rrc_nr::rrc_nr(srslte::timer_handler* timers_) : - m_log("RRC"), - pool(srslte::byte_buffer_pool::get_instance()), - timers(timers_) + m_log("RRC"), pool(srslte::byte_buffer_pool::get_instance()), timers(timers_) {} void rrc_nr::init(const rrc_nr_cfg_t& cfg_, @@ -388,4 +386,4 @@ void rrc_nr::ue::send_dl_ccch(dl_ccch_msg_s* dl_ccch_msg) parent->rlc->write_sdu(rnti, RB_ID_SRB0, std::move(pdu)); } -} // namespace srsenb \ No newline at end of file +} // namespace srsenb diff --git a/srsenb/src/stack/upper/pdcp.cc b/srsenb/src/stack/upper/pdcp.cc index d66892cdd..3c06acf73 100644 --- a/srsenb/src/stack/upper/pdcp.cc +++ b/srsenb/src/stack/upper/pdcp.cc @@ -139,6 +139,13 @@ void pdcp::write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t } } +void pdcp::notify_delivery(uint16_t rnti, uint32_t lcid, const std::vector& pdcp_sns) +{ + if (users.count(rnti)) { + users[rnti].pdcp->notify_delivery(lcid, pdcp_sns); + } +} + void pdcp::write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu, int pdcp_sn) { if (users.count(rnti)) { diff --git a/srsenb/src/stack/upper/pdcp_nr.cc b/srsenb/src/stack/upper/pdcp_nr.cc index 5397489a2..4244a2207 100644 --- a/srsenb/src/stack/upper/pdcp_nr.cc +++ b/srsenb/src/stack/upper/pdcp_nr.cc @@ -16,9 +16,7 @@ namespace srsenb { pdcp_nr::pdcp_nr(srslte::task_sched_handle task_sched_, const char* logname) : - task_sched(task_sched_), - m_log(logname), - pool(srslte::byte_buffer_pool::get_instance()) + task_sched(task_sched_), m_log(logname), pool(srslte::byte_buffer_pool::get_instance()) {} void pdcp_nr::init(const pdcp_nr_args_t& args_, @@ -102,6 +100,15 @@ void pdcp_nr::write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer } } +void pdcp_nr::notify_delivery(uint16_t rnti, uint32_t lcid, const std::vector& pdcp_sns) +{ + if (users.count(rnti)) { + users[rnti].pdcp->notify_delivery(lcid, pdcp_sns); + } else { + m_log->error("Can't notify Ack of PDU. RNTI=0x%X doesn't exist.\n", rnti); + } +} + void pdcp_nr::write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) { if (users.count(rnti)) { @@ -161,4 +168,4 @@ std::string pdcp_nr::user_interface_rrc::get_rb_name(uint32_t lcid) return srslte::to_string(static_cast(lcid)); } -} // namespace srsenb \ No newline at end of file +} // namespace srsenb diff --git a/srsenb/src/stack/upper/rlc.cc b/srsenb/src/stack/upper/rlc.cc index dc774e001..d2c762f27 100644 --- a/srsenb/src/stack/upper/rlc.cc +++ b/srsenb/src/stack/upper/rlc.cc @@ -268,6 +268,11 @@ void rlc::user_interface::write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t } } +void rlc::user_interface::notify_delivery(uint32_t lcid, const std::vector& pdcp_sns) +{ + pdcp->notify_delivery(rnti, lcid, pdcp_sns); +} + void rlc::user_interface::write_pdu_bcch_bch(srslte::unique_byte_buffer_t sdu) { ERROR("Error: Received BCCH from ue=%d", rnti); diff --git a/srsenb/src/stack/upper/rlc_nr.cc b/srsenb/src/stack/upper/rlc_nr.cc index db62ed073..7a6beb6aa 100644 --- a/srsenb/src/stack/upper/rlc_nr.cc +++ b/srsenb/src/stack/upper/rlc_nr.cc @@ -207,4 +207,9 @@ std::string rlc_nr::user_interface::get_rb_name(uint32_t lcid) return srslte::to_string(static_cast(lcid)); } -} // namespace srsenb \ No newline at end of file +void rlc_nr::user_interface::notify_delivery(uint32_t lcid, const std::vector& pdcp_sns) +{ + m_pdcp->notify_delivery(rnti, lcid, pdcp_sns); +} + +} // namespace srsenb