From de90b4753f328b9acc053477161203b6dbb096f1 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Tue, 15 Sep 2020 12:21:39 +0100 Subject: [PATCH] Added the ability of the RLC AM to notify the PDCP of the acknowledged PDCP PDUs. This includes: - Modifying the byte_buffer_t to include PDCP SN meta-data. This way, the RLC can keep track of the ack'ed bytes for a specific PDCP PDU. - Added in the RLC an `undelivered_sdu_info queue`, to keep track of the amount of ack'ed bytes and the total size of the PDCP PDU, so the RLC can know when delivery is finished. - Added an interface between the PDCP and the RLC so that the RLC can notify the PDCP when it receives an ack from the status PDUs. The RLC passes to the PDCP a vector of all the ack'ed pdus in a rx'ed status PDU. - Added some tests to the notify functionality. This includes some tests where the PDUs are acked imediatly, and one test where the PDU is retx'ed. --- lib/include/srslte/common/common.h | 7 + .../srslte/interfaces/enb_interfaces.h | 3 +- .../srslte/interfaces/gnb_interfaces.h | 5 +- lib/include/srslte/interfaces/ue_interfaces.h | 19 +- lib/include/srslte/upper/pdcp.h | 1 + lib/include/srslte/upper/pdcp_entity_base.h | 3 +- lib/include/srslte/upper/pdcp_entity_lte.h | 1 + lib/include/srslte/upper/pdcp_entity_nr.h | 1 + lib/include/srslte/upper/rlc_am_lte.h | 21 +- lib/include/srslte/upper/rlc_common.h | 6 +- lib/src/upper/pdcp.cc | 9 + lib/src/upper/pdcp_entity_lte.cc | 15 +- lib/src/upper/pdcp_entity_nr.cc | 13 +- lib/src/upper/rlc_am_lte.cc | 63 ++- lib/test/upper/CMakeLists.txt | 4 + lib/test/upper/rlc_am_notify_pdcp_test.cc | 516 ++++++++++++++++++ lib/test/upper/rlc_am_test.cc | 1 + lib/test/upper/rlc_common_test.cc | 1 + lib/test/upper/rlc_stress_test.cc | 12 +- lib/test/upper/rlc_test_common.h | 1 + srsenb/hdr/stack/gnb_stack_nr.h | 4 +- srsenb/hdr/stack/upper/pdcp.h | 1 + srsenb/hdr/stack/upper/pdcp_nr.h | 3 +- srsenb/hdr/stack/upper/rlc.h | 1 + srsenb/hdr/stack/upper/rlc_nr.h | 3 +- srsenb/src/stack/rrc/rrc_nr.cc | 6 +- srsenb/src/stack/upper/pdcp.cc | 7 + srsenb/src/stack/upper/pdcp_nr.cc | 15 +- srsenb/src/stack/upper/rlc.cc | 5 + srsenb/src/stack/upper/rlc_nr.cc | 7 +- 30 files changed, 702 insertions(+), 52 deletions(-) create mode 100644 lib/test/upper/rlc_am_notify_pdcp_test.cc 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