From 7ac7c8673ab7cf38a12829aaa8bafccd97ec8cdc Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Thu, 7 Jul 2022 15:55:59 +0100 Subject: [PATCH] lib,rlc: Fixed issue where `p` bit was not checked if PDU was outside of the RX window. This could lead to a data stall, where TX keeps retx'ing the same PDU to request a status report. --- lib/src/rlc/rlc_am_nr.cc | 22 +++--- lib/test/rlc/rlc_am_lte_test.cc | 104 +++++++++++++------------- lib/test/rlc/rlc_am_nr_test.cc | 127 +++++++++++++++++++++++++------- lib/test/rlc/rlc_test_common.h | 7 +- 4 files changed, 172 insertions(+), 88 deletions(-) diff --git a/lib/src/rlc/rlc_am_nr.cc b/lib/src/rlc/rlc_am_nr.cc index 6acd14acc..da27b2587 100644 --- a/lib/src/rlc/rlc_am_nr.cc +++ b/lib/src/rlc/rlc_am_nr.cc @@ -1425,21 +1425,25 @@ void rlc_am_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes) RlcHexInfo(payload, nof_bytes, "Rx data PDU SN=%d (%d B)", header.sn, nof_bytes); log_rlc_am_nr_pdu_header_to_string(logger.debug, header, rb_name); + // Trigger polling if poll bit is set. + // We do this before checking if the PDU is inside the RX window, + // as the RX window may have advanced without the TX having received the ACKs + // This can cause a data stall, whereby the TX keeps retransmiting + // a PDU outside of the Rx window. + // Also, we do this before discarding duplicate SDUs/SDU segments + // Because t-PollRetransmit may transmit a PDU that was already + // received. + if (header.p != 0U) { + RlcInfo("status packet requested through polling bit"); + do_status = true; + } + // Check whether SDU is within Rx Window if (!inside_rx_window(header.sn)) { RlcInfo("SN=%d outside rx window [%d:%d] - discarding", header.sn, st.rx_next, st.rx_next + rx_window_size()); return; } - // Trigger polling if poll bit is set. - // We do this before discarding duplicate SDUs/SDU segments - // Because t-PollRetransmit may transmit a PDU that was already - // received. - if (header.p) { - RlcInfo("status packet requested through polling bit"); - do_status = true; - } - // Section 5.2.3.2.2, discard duplicate PDUs if (rx_window->has_sn(header.sn) && (*rx_window)[header.sn].fully_received) { RlcInfo("discarding duplicate SN=%d", header.sn); diff --git a/lib/test/rlc/rlc_am_lte_test.cc b/lib/test/rlc/rlc_am_lte_test.cc index 9ad201ef1..984d6afdd 100644 --- a/lib/test/rlc/rlc_am_lte_test.cc +++ b/lib/test/rlc/rlc_am_lte_test.cc @@ -96,7 +96,7 @@ int basic_test_tx(rlc_am* rlc, byte_buffer_t pdu_bufs[NBUFS]) int basic_test() { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); byte_buffer_t pdu_bufs[NBUFS]; @@ -155,7 +155,7 @@ int basic_test() int concat_test() { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); srsran::timer_handler timers(8); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); @@ -229,7 +229,7 @@ int concat_test() int segment_test(bool in_seq_rx) { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); srsran::timer_handler timers(8); int len = 0; @@ -324,7 +324,7 @@ int segment_test(bool in_seq_rx) int retx_test() { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); int len = 0; @@ -460,7 +460,7 @@ int retx_test() // Test correct upper layer signaling when maxRetx (default 4) have been reached int max_retx_test() { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); int len = 0; @@ -523,7 +523,7 @@ int max_retx_test() // Purpose: test correct retx of lost segment and pollRetx timer expiration int segment_retx_test() { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); int len = 0; @@ -648,7 +648,7 @@ int resegment_test_1() // PDUs: | 10 | 10 | 10 | 10 | 10 | // Retx PDU segments: | 5 | 5| - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); int len = 0; @@ -806,7 +806,7 @@ int resegment_test_2() // PDUs: | 5 | 10 | 20 | 10 | 5 | // Retx PDU segments: | 10 | 10 | - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); @@ -938,7 +938,7 @@ int resegment_test_3() // PDUs: | 5 | 5| 20 | 10 | 10 | // Retx PDU segments: | 10 | 10 | - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); srsran::timer_handler timers(8); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); @@ -1068,7 +1068,7 @@ int resegment_test_4() // PDUs: | 5 | 5| 30 | 5 | 5| // Retx PDU segments: | 15 | 15 | - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); srsran::timer_handler timers(8); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); @@ -1200,7 +1200,7 @@ int resegment_test_5() // PDUs: |2|3| 40 |3|2| // Retx PDU segments: | 20 | 20 | - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); srsran::timer_handler timers(8); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); @@ -1326,7 +1326,7 @@ int resegment_test_6() // PDUs: |10|10|10| 270 | 54 | // Retx PDU segments: | 120 | 150 | - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); srsran::timer_handler timers(8); int len = 0; @@ -1493,9 +1493,9 @@ int resegment_test_7() #if HAVE_PCAP rlc_pcap pcap; pcap.open("rlc_am_test7.pcap", rlc_config_t::default_rlc_am_config()); - rlc_am_tester tester(&pcap); + rlc_am_tester tester(true, &pcap); #else - rlc_am_tester tester(NULL); + rlc_am_tester tester(true, nullptr); #endif srsran::timer_handler timers(8); @@ -1678,9 +1678,9 @@ int resegment_test_8() #if HAVE_PCAP rlc_pcap pcap; pcap.open("rlc_am_test8.pcap", rlc_config_t::default_rlc_am_config()); - rlc_am_tester tester(&pcap); + rlc_am_tester tester(true, &pcap); #else - rlc_am_tester tester(NULL); + rlc_am_tester tester(true, nullptr); #endif srsran::timer_handler timers(8); @@ -1830,9 +1830,9 @@ int resegment_test_9() #if HAVE_PCAP rlc_pcap pcap; pcap.open("rlc_resegment_test_9.pcap", config); - rlc_am_tester tester(&pcap); + rlc_am_tester tester(true, &pcap); #else - rlc_am_tester tester(NULL); + rlc_am_tester tester(true, nullptr); #endif srsran::timer_handler timers(8); @@ -1972,9 +1972,9 @@ int resegment_test_10() #if HAVE_PCAP rlc_pcap pcap; pcap.open("rlc_resegment_test_10.pcap", config); - rlc_am_tester tester(&pcap); + rlc_am_tester tester(true, &pcap); #else - rlc_am_tester tester(NULL); + rlc_am_tester tester(true, NULL); #endif srsran::timer_handler timers(8); @@ -2121,9 +2121,9 @@ int resegment_test_11() #if HAVE_PCAP rlc_pcap pcap; pcap.open("rlc_resegment_test_11.pcap", config); - rlc_am_tester tester(&pcap); + rlc_am_tester tester(true, &pcap); #else - rlc_am_tester tester(NULL); + rlc_am_tester tester(true, NULL); #endif srsran::timer_handler timers(8); @@ -2279,9 +2279,9 @@ int resegment_test_12() #if HAVE_PCAP rlc_pcap pcap; pcap.open("rlc_resegment_test_12.pcap", config); - rlc_am_tester tester(&pcap); + rlc_am_tester tester(true, &pcap); #else - rlc_am_tester tester(NULL); + rlc_am_tester tester(true, NULL); #endif srsran::timer_handler timers(8); @@ -2423,9 +2423,9 @@ int header_reconstruction_test(srsran::log_sink_message_spy& spy) #if HAVE_PCAP rlc_pcap pcap; pcap.open("rlc_am_header_reconstruction_test.pcap", rlc_config_t::default_rlc_am_config()); - rlc_am_tester tester(&pcap); + rlc_am_tester tester(true, &pcap); #else - rlc_am_tester tester(NULL); + rlc_am_tester tester(true, NULL); #endif srsran::timer_handler timers(8); @@ -2486,9 +2486,9 @@ int header_reconstruction_test2(srsran::log_sink_message_spy& spy) #if HAVE_PCAP rlc_pcap pcap; pcap.open("rlc_am_header_reconstruction_test2.pcap", rlc_config_t::default_rlc_am_config()); - rlc_am_tester tester(&pcap); + rlc_am_tester tester(true, &pcap); #else - rlc_am_tester tester(NULL); + rlc_am_tester tester(true, NULL); #endif srsran::timer_handler timers(8); @@ -2549,9 +2549,9 @@ int header_reconstruction_test3(srsran::log_sink_message_spy& spy) #if HAVE_PCAP rlc_pcap pcap; pcap.open("rlc_am_header_reconstruction_test3.pcap", rlc_config_t::default_rlc_am_config()); - rlc_am_tester tester(&pcap); + rlc_am_tester tester(true, &pcap); #else - rlc_am_tester tester(NULL); + rlc_am_tester tester(true, NULL); #endif srsran::timer_handler timers(8); @@ -2635,9 +2635,9 @@ int header_reconstruction_test4(srsran::log_sink_message_spy& spy) #if HAVE_PCAP rlc_pcap pcap; pcap.open("rlc_am_header_reconstruction_test4.pcap", rlc_config_t::default_rlc_am_config()); - rlc_am_tester tester(&pcap); + rlc_am_tester tester(true, &pcap); #else - rlc_am_tester tester(NULL); + rlc_am_tester tester(true, NULL); #endif srsran::timer_handler timers(8); @@ -2712,9 +2712,9 @@ int header_reconstruction_test5(srsran::log_sink_message_spy& spy) #if HAVE_PCAP rlc_pcap pcap; pcap.open("rlc_am_header_reconstruction_test5.pcap", rlc_config_t::default_rlc_am_config()); - rlc_am_tester tester(&pcap); + rlc_am_tester tester(true, &pcap); #else - rlc_am_tester tester(NULL); + rlc_am_tester tester(true, NULL); #endif srsran::timer_handler timers(8); @@ -2791,9 +2791,9 @@ int header_reconstruction_test6(srsran::log_sink_message_spy& spy) #if HAVE_PCAP rlc_pcap pcap; pcap.open("rlc_am_header_reconstruction_test6.pcap", rlc_config_t::default_rlc_am_config()); - rlc_am_tester tester(&pcap); + rlc_am_tester tester(true, &pcap); #else - rlc_am_tester tester(NULL); + rlc_am_tester tester(true, NULL); #endif srsran::timer_handler timers(8); @@ -2890,9 +2890,9 @@ int header_reconstruction_test7(srsran::log_sink_message_spy& spy) #if HAVE_PCAP rlc_pcap pcap; pcap.open("rlc_am_header_reconstruction_test7.pcap", rlc_config_t::default_rlc_am_config()); - rlc_am_tester tester(&pcap); + rlc_am_tester tester(true, &pcap); #else - rlc_am_tester tester(NULL); + rlc_am_tester tester(true, NULL); #endif srsran::timer_handler timers(8); @@ -2992,9 +2992,9 @@ int header_reconstruction_test8(srsran::log_sink_message_spy& spy) #if HAVE_PCAP rlc_pcap pcap; pcap.open("rlc_am_header_reconstruction_test8.pcap", rlc_config_t::default_rlc_am_config()); - rlc_am_tester tester(&pcap); + rlc_am_tester tester(true, &pcap); #else - rlc_am_tester tester(NULL); + rlc_am_tester tester(true, NULL); #endif srsran::timer_handler timers(8); @@ -3026,7 +3026,7 @@ int header_reconstruction_test8(srsran::log_sink_message_spy& spy) bool reset_test() { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); srsran::timer_handler timers(8); int len = 0; @@ -3068,7 +3068,7 @@ bool reset_test() bool resume_test() { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); srsran::timer_handler timers(8); int len = 0; @@ -3110,7 +3110,7 @@ bool resume_test() bool stop_test() { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); srsran::timer_handler timers(8); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); @@ -3136,7 +3136,7 @@ bool stop_test() // be enough to fit all SNs that would need to be NACKed bool status_pdu_test() { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); srsran::timer_handler timers(8); int len = 0; @@ -3245,7 +3245,7 @@ bool status_pdu_test() // The incidence is reported to the upper layers. bool incorrect_status_pdu_test() { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); srsran::timer_handler timers(8); int len = 0; @@ -3310,7 +3310,7 @@ bool incorrect_status_pdu_test() /// In contrast to the without explicitly NACK-ing specific SNs bool incorrect_status_pdu_test2() { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); srsran::timer_handler timers(8); int len = 0; @@ -3421,9 +3421,9 @@ bool reestablish_test() #if HAVE_PCAP rlc_pcap pcap; pcap.open("rlc_am_reestablish_test.pcap", config); - rlc_am_tester tester(&pcap); + rlc_am_tester tester(true, &pcap); #else - rlc_am_tester tester(NULL); + rlc_am_tester tester(true, nullptr); #endif srsran::timer_handler timers(8); @@ -3541,9 +3541,9 @@ bool discard_test() #if HAVE_PCAP rlc_pcap pcap; pcap.open("rlc_am_reestablish_test.pcap", config); - rlc_am_tester tester(&pcap); + rlc_am_tester tester(true, &pcap); #else - rlc_am_tester tester(NULL); + rlc_am_tester tester(true, NULL); #endif srsran::timer_handler timers(8); @@ -3631,9 +3631,9 @@ bool poll_retx_expiry_test() #if HAVE_PCAP rlc_pcap pcap; pcap.open("rlc_am_poll_rext_expiry_test.pcap", config); - rlc_am_tester tester(&pcap); + rlc_am_tester tester(true, &pcap); #else - rlc_am_tester tester(NULL); + rlc_am_tester tester(true, NULL); #endif srsran::timer_handler timers(8); diff --git a/lib/test/rlc/rlc_am_nr_test.cc b/lib/test/rlc/rlc_am_nr_test.cc index 3567092af..24788e1d9 100644 --- a/lib/test/rlc/rlc_am_nr_test.cc +++ b/lib/test/rlc/rlc_am_nr_test.cc @@ -60,7 +60,7 @@ int basic_test_tx(rlc_am* rlc, byte_buffer_t pdu_bufs[NBUFS], rlc_am_nr_sn_size_ */ int window_checker_test(rlc_am_nr_sn_size_t sn_size) { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); auto& test_logger = srslog::fetch_basic_logger("TESTER "); @@ -124,7 +124,7 @@ int window_checker_test(rlc_am_nr_sn_size_t sn_size) */ int retx_segmentation_required_checker_test(rlc_am_nr_sn_size_t sn_size) { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); auto& test_logger = srslog::fetch_basic_logger("TESTER "); @@ -210,7 +210,7 @@ int retx_segmentation_required_checker_test(rlc_am_nr_sn_size_t sn_size) */ int basic_test(rlc_am_nr_sn_size_t sn_size) { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); byte_buffer_t pdu_bufs[NBUFS]; @@ -318,7 +318,7 @@ int basic_test(rlc_am_nr_sn_size_t sn_size) */ int lost_pdu_test(rlc_am_nr_sn_size_t sn_size) { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); byte_buffer_t pdu_bufs[NBUFS]; @@ -493,7 +493,7 @@ int lost_pdu_test(rlc_am_nr_sn_size_t sn_size) */ int lost_pdu_duplicated_nack_test(rlc_am_nr_sn_size_t sn_size) { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); byte_buffer_t pdu_bufs[NBUFS]; @@ -678,7 +678,7 @@ int lost_pdu_duplicated_nack_test(rlc_am_nr_sn_size_t sn_size) */ int lost_pdus_trimmed_nack_test(rlc_am_nr_sn_size_t sn_size) { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); byte_buffer_t pdu_bufs[NBUFS]; @@ -897,7 +897,7 @@ int lost_pdus_trimmed_nack_test(rlc_am_nr_sn_size_t sn_size) */ int clean_retx_queue_of_acked_sdus_test(rlc_am_nr_sn_size_t sn_size) { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); byte_buffer_t pdu_bufs[NBUFS]; @@ -1085,7 +1085,7 @@ int clean_retx_queue_of_acked_sdus_test(rlc_am_nr_sn_size_t sn_size) */ int basic_segmentation_test(rlc_am_nr_sn_size_t sn_size) { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); auto& test_logger = srslog::fetch_basic_logger("TESTER "); test_delimit_logger delimiter("basic segmentation ({} bit SN)", to_number(sn_size)); @@ -1177,7 +1177,7 @@ int basic_segmentation_test(rlc_am_nr_sn_size_t sn_size) // - Check metrics and state int segment_retx_test(rlc_am_nr_sn_size_t sn_size) { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); byte_buffer_t pdu_bufs[NBUFS]; @@ -1376,7 +1376,7 @@ int segment_retx_test(rlc_am_nr_sn_size_t sn_size) // - Check metrics and state int segment_retx_and_loose_segments_test(rlc_am_nr_sn_size_t sn_size) { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); byte_buffer_t pdu_bufs[NBUFS]; @@ -1640,7 +1640,7 @@ int segment_retx_and_loose_segments_test(rlc_am_nr_sn_size_t sn_size) int retx_segment_test(rlc_am_nr_sn_size_t sn_size) { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); auto& test_logger = srslog::fetch_basic_logger("TESTER "); @@ -1958,7 +1958,7 @@ int retx_segment_test(rlc_am_nr_sn_size_t sn_size) // SN==TX_NEXT. int handle_status_of_non_tx_last_segment(rlc_am_nr_sn_size_t sn_size) { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); auto& test_logger = srslog::fetch_basic_logger("TESTER "); test_delimit_logger delimiter("basic segmentation ({} bit SN)", to_number(sn_size)); @@ -2045,7 +2045,7 @@ int handle_status_of_non_tx_last_segment(rlc_am_nr_sn_size_t sn_size) // due to lost SDUs as a whole int max_retx_lost_sdu_test(rlc_am_nr_sn_size_t sn_size) { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); int len = 0; @@ -2120,7 +2120,7 @@ int max_retx_lost_sdu_test(rlc_am_nr_sn_size_t sn_size) // due to lost SDU segments int max_retx_lost_segments_test(rlc_am_nr_sn_size_t sn_size) { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); int len = 0; @@ -2249,7 +2249,7 @@ int max_retx_lost_segments_test(rlc_am_nr_sn_size_t sn_size) // This test checks the correct functioning of RLC discard functionality int discard_test(rlc_am_nr_sn_size_t sn_size) { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); auto& test_logger = srslog::fetch_basic_logger("TESTER "); @@ -2355,7 +2355,7 @@ int discard_test(rlc_am_nr_sn_size_t sn_size) // Test p bit set on new TX with PollPDU int poll_pdu(rlc_am_nr_sn_size_t sn_size) { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); auto& test_logger = srslog::fetch_basic_logger("TESTER "); @@ -2411,7 +2411,7 @@ int poll_pdu(rlc_am_nr_sn_size_t sn_size) // Test p bit set on new TX with PollBYTE int poll_byte(rlc_am_nr_sn_size_t sn_size) { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); auto& test_logger = srslog::fetch_basic_logger("TESTER "); @@ -2467,7 +2467,7 @@ int poll_byte(rlc_am_nr_sn_size_t sn_size) // Test p bit set on RETXes that cause an empty retx queue. int poll_retx(rlc_am_nr_sn_size_t sn_size) { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); auto& test_logger = srslog::fetch_basic_logger("TESTER "); @@ -2585,7 +2585,7 @@ int poll_retx(rlc_am_nr_sn_size_t sn_size) // It checks if the poll retx timer is re-armed upon receiving an ACK for POLL_SN bool poll_retx_expiry(rlc_am_nr_sn_size_t sn_size) { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); auto& test_logger = srslog::fetch_basic_logger("TESTER "); @@ -2740,7 +2740,7 @@ bool poll_retx_expiry(rlc_am_nr_sn_size_t sn_size) int rx_nack_range_no_so_test(rlc_am_nr_sn_size_t sn_size) { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); auto& test_logger = srslog::fetch_basic_logger("TESTER "); @@ -2832,7 +2832,7 @@ int rx_nack_range_no_so_test(rlc_am_nr_sn_size_t sn_size) int rx_nack_range_with_so_test(rlc_am_nr_sn_size_t sn_size) { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); auto& test_logger = srslog::fetch_basic_logger("TESTER "); @@ -2928,7 +2928,7 @@ int rx_nack_range_with_so_test(rlc_am_nr_sn_size_t sn_size) int rx_nack_range_with_so_starting_with_full_sdu_test(rlc_am_nr_sn_size_t sn_size) { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); auto& test_logger = srslog::fetch_basic_logger("TESTER "); @@ -3035,7 +3035,7 @@ int rx_nack_range_with_so_starting_with_full_sdu_test(rlc_am_nr_sn_size_t sn_siz int rx_nack_range_with_so_ending_with_full_sdu_test(rlc_am_nr_sn_size_t sn_size) { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); auto& test_logger = srslog::fetch_basic_logger("TESTER "); @@ -3142,7 +3142,7 @@ int rx_nack_range_with_so_ending_with_full_sdu_test(rlc_am_nr_sn_size_t sn_size) int out_of_order_status(rlc_am_nr_sn_size_t sn_size) { - rlc_am_tester tester; + rlc_am_tester tester(true, nullptr); timer_handler timers(8); byte_buffer_t pdu_bufs[NBUFS]; @@ -3210,9 +3210,85 @@ int out_of_order_status(rlc_am_nr_sn_size_t sn_size) return SRSRAN_SUCCESS; } +// If we lose the status report +int lost_status_and_advanced_rx_window(rlc_am_nr_sn_size_t sn_size) +{ + rlc_am_tester tester(true, nullptr); + timer_handler timers(8); + byte_buffer_t pdu_bufs[NBUFS]; + + auto& test_logger = srslog::fetch_basic_logger("TESTER "); + test_delimit_logger delimiter("Lost status report and advance RX window ({} bit SN)", to_number(sn_size)); + rlc_am rlc1(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); + rlc_am rlc2(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); + + rlc_am_nr_tx* tx1 = dynamic_cast(rlc1.get_tx()); + rlc_am_nr_rx* rx1 = dynamic_cast(rlc1.get_rx()); + rlc_am_nr_tx* tx2 = dynamic_cast(rlc2.get_tx()); + rlc_am_nr_rx* rx2 = dynamic_cast(rlc2.get_rx()); + + auto cfg = rlc_config_t::default_rlc_am_nr_config(to_number(sn_size)); + if (not rlc1.configure(cfg)) { + return -1; + } + if (not rlc2.configure(cfg)) { + return -1; + } + uint32_t mod_nr = cardinality(cfg.am_nr.tx_sn_field_length); + + // Fill up the RX window + constexpr uint32_t payload_size = 3; // Give the SDU the size of 3 bytes + uint32_t header_size = sn_size == rlc_am_nr_sn_size_t::size12bits ? 2 : 3; + for (uint32_t sn = 0; sn < 10; ++sn) { + // Write SDU + unique_byte_buffer_t sdu_buf = srsran::make_byte_buffer(); + sdu_buf->msg[0] = sn; // Write the index into the buffer + sdu_buf->N_bytes = payload_size; // Give each buffer a size of 3 bytes + sdu_buf->md.pdcp_sn = sn; // PDCP SN for notifications + rlc1.write_sdu(std::move(sdu_buf)); + + // Read PDU + unique_byte_buffer_t pdu_buf = srsran::make_byte_buffer(); + pdu_buf->N_bytes = rlc1.read_pdu(pdu_buf->msg, 100); + + // Write PDU into RLC 2 + // We receive all PDUs + rlc2.write_pdu(pdu_buf->msg, pdu_buf->N_bytes); + } + + // We got the polling bit, so we generate the status report. + TESTASSERT_EQ(3, rlc2.get_buffer_state()); + + // Read status PDU + { + unique_byte_buffer_t status_buf = srsran::make_byte_buffer(); + status_buf->N_bytes = rlc2.read_pdu(status_buf->msg, 3); + } + TESTASSERT_EQ(0, rlc2.get_buffer_state()); + + // We do not write the status report into RLC 1 + // We step trought the timers to let t-PollRetransmission expire + TESTASSERT_EQ(0, rlc1.get_buffer_state()); + for (int t = 0; t < 45; t++) { + timers.step_all(); + } + TESTASSERT_EQ(header_size + payload_size, rlc1.get_buffer_state()); + + // Read RETX of POLL_SN and check if it triggered the + // Status report + { + unique_byte_buffer_t pdu_buf = srsran::make_byte_buffer(); + pdu_buf->N_bytes = rlc1.read_pdu(pdu_buf->msg, 100); + TESTASSERT_EQ(0, rlc2.get_buffer_state()); + rlc2.write_pdu(pdu_buf->msg, pdu_buf->N_bytes); + TESTASSERT_EQ(3, rlc2.get_buffer_state()); + } + + return SRSRAN_SUCCESS; +} int full_rx_window_t_reassembly_expiry(rlc_am_nr_sn_size_t sn_size) { - rlc_am_tester tester; + rlc_am_tester tester(false, nullptr); timer_handler timers(8); byte_buffer_t pdu_bufs[NBUFS]; @@ -3330,6 +3406,7 @@ int main() TESTASSERT(rx_nack_range_with_so_starting_with_full_sdu_test(sn_size) == SRSRAN_SUCCESS); TESTASSERT(rx_nack_range_with_so_ending_with_full_sdu_test(sn_size) == SRSRAN_SUCCESS); TESTASSERT(out_of_order_status(sn_size) == SRSRAN_SUCCESS); + TESTASSERT(lost_status_and_advanced_rx_window(sn_size) == SRSRAN_SUCCESS); } TESTASSERT(full_rx_window_t_reassembly_expiry(rlc_am_nr_sn_size_t::size12bits) == SRSRAN_SUCCESS); return SRSRAN_SUCCESS; diff --git a/lib/test/rlc/rlc_test_common.h b/lib/test/rlc/rlc_test_common.h index 3b76231af..1a641425b 100644 --- a/lib/test/rlc/rlc_test_common.h +++ b/lib/test/rlc/rlc_test_common.h @@ -72,13 +72,15 @@ public: class rlc_am_tester : public srsue::pdcp_interface_rlc, public srsue::rrc_interface_rlc { public: - rlc_am_tester(rlc_pcap* pcap_ = NULL) : pcap(pcap_) {} + explicit rlc_am_tester(bool save_sdus_, rlc_pcap* pcap_) : save_sdus(save_sdus_), pcap(pcap_) {} // PDCP interface void write_pdu(uint32_t lcid, unique_byte_buffer_t sdu) { assert(lcid == 1); - // sdus.push_back(std::move(sdu)); + if (save_sdus) { + sdus.push_back(std::move(sdu)); + } } void write_pdu_bcch_bch(unique_byte_buffer_t sdu) {} void write_pdu_bcch_dlsch(unique_byte_buffer_t sdu) {} @@ -110,6 +112,7 @@ public: rlc_pcap* pcap = nullptr; bool max_retx_triggered = false; bool protocol_failure_triggered = false; + bool save_sdus = true; std::map notified_counts; // Map of PDCP SNs to number of notifications };