From 76c33c78a96ac49e5216f443c3e8f6bc4704dc43 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Tue, 30 Nov 2021 16:26:19 +0000 Subject: [PATCH] lib,rlc_am_nr: starting to add test for segmentation. Starting to add functions for creating new segments and segment continuation. --- lib/include/srsran/rlc/rlc_am_nr.h | 17 +++++- lib/include/srsran/rlc/rlc_am_nr_packing.h | 10 ++++ lib/src/rlc/rlc_am_nr.cc | 61 ++++++++++++++++------ lib/test/rlc/rlc_am_nr_test.cc | 44 ++++++++++------ 4 files changed, 99 insertions(+), 33 deletions(-) diff --git a/lib/include/srsran/rlc/rlc_am_nr.h b/lib/include/srsran/rlc/rlc_am_nr.h index 62e56d061..5482444b9 100644 --- a/lib/include/srsran/rlc/rlc_am_nr.h +++ b/lib/include/srsran/rlc/rlc_am_nr.h @@ -90,10 +90,22 @@ public: // Data PDU helpers using rlc_amd_tx_pdu_nr = rlc_amd_tx_pdu; + /* + struct rlc_amd_tx_pdu_nr { + const uint32_t rlc_sn = INVALID_RLC_SN; + const uint32_t pdcp_sn = INVALID_RLC_SN; + struct tx_pdu_segment { + rlc_am_nr_pdu_header_t header = {}; + uint32_t retx_count = 0; + uint32_t so = 0; + uint32_t len = 0; + }; + };*/ int build_new_sdu_segment(const unique_byte_buffer_t& tx_sdu, rlc_amd_tx_pdu_nr& tx_pdu, uint8_t* payload, uint32_t nof_bytes); + int build_continuation_sdu_segment(rlc_amd_tx_pdu_nr& tx_pdu, uint8_t* payload, uint32_t nof_bytes); int build_retx_pdu(unique_byte_buffer_t& tx_pdu, uint32_t nof_bytes); // Buffer State @@ -131,7 +143,10 @@ private: ***************************************************************************/ struct rlc_am_nr_tx_state_t st = {}; rlc_ringbuffer_t tx_window; - pdu_retx_queue retx_queue; + + // Queues and buffers + pdu_retx_queue retx_queue; + rlc_amd_tx_sdu_nr_t current_sdu; // Currently SDU beind segmented public: // Getters/Setters diff --git a/lib/include/srsran/rlc/rlc_am_nr_packing.h b/lib/include/srsran/rlc/rlc_am_nr_packing.h index 73564665e..44592755d 100644 --- a/lib/include/srsran/rlc/rlc_am_nr_packing.h +++ b/lib/include/srsran/rlc/rlc_am_nr_packing.h @@ -18,6 +18,8 @@ namespace srsran { +const uint32_t INVALID_RLC_SN = 0xFFFFFFFF; + ///< AM NR PDU header struct rlc_am_nr_pdu_header_t { rlc_am_nr_pdu_header_t() = default; @@ -60,6 +62,14 @@ struct rlc_amd_rx_sdu_nr_t { explicit rlc_amd_rx_sdu_nr_t(uint32_t rlc_sn_) : rlc_sn(rlc_sn_) {} }; +struct rlc_amd_tx_sdu_nr_t { + uint32_t rlc_sn = INVALID_RLC_SN; + unique_byte_buffer_t buf; + + rlc_amd_tx_sdu_nr_t() = default; + explicit rlc_amd_tx_sdu_nr_t(uint32_t rlc_sn_) : rlc_sn(rlc_sn_) {} +}; + ///< AM NR Status PDU header (perhaps merge with LTE version) typedef struct { rlc_am_nr_control_pdu_type_t cpt; diff --git a/lib/src/rlc/rlc_am_nr.cc b/lib/src/rlc/rlc_am_nr.cc index 30adbfccb..5bc95e8fe 100644 --- a/lib/src/rlc/rlc_am_nr.cc +++ b/lib/src/rlc/rlc_am_nr.cc @@ -87,9 +87,6 @@ uint32_t rlc_am_nr_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes) return tx_pdu->N_bytes; } - // Section 5.2.2.3 in TS 36.311, if tx_window is full and retx_queue empty, retransmit PDU - // TODO - // RETX if required if (not retx_queue.empty()) { logger->info("Retx required. Retx queue size: %d", retx_queue.size()); @@ -105,6 +102,17 @@ uint32_t rlc_am_nr_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes) } } + // Send remaining segment, if it exists + if (current_sdu.rlc_sn != INVALID_RLC_SN) { + if (not tx_window.has_sn(current_sdu.rlc_sn)) { + current_sdu.rlc_sn = INVALID_RLC_SN; + logger->error("SDU currently being segmented does not exist in tx_window. Aborting segmenttion SN=%d", + current_sdu.rlc_sn); + return 0; + } + return build_continuation_sdu_segment(tx_window[current_sdu.rlc_sn], payload, nof_bytes); + } + // Check wether there is something to TX if (tx_sdu_queue.is_empty()) { logger->info("No data available to be sent"); @@ -138,10 +146,7 @@ uint32_t rlc_am_nr_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes) uint16_t hdr_size = 2; if (tx_sdu->N_bytes + hdr_size > nof_bytes) { logger->info("Trying to build PDU segment from SDU."); - if (build_new_sdu_segment(tx_sdu, tx_pdu, payload, nof_bytes) != SRSRAN_SUCCESS) { - return 0; - } - return tx_pdu.buf->N_bytes; + return build_new_sdu_segment(tx_sdu, tx_pdu, payload, nof_bytes); } memcpy(tx_pdu.buf->msg, tx_sdu->msg, tx_sdu->N_bytes); @@ -177,16 +182,23 @@ int rlc_am_nr_tx::build_new_sdu_segment(const unique_byte_buffer_t& tx_sdu, uint8_t* payload, uint32_t nof_bytes) { + logger->info("Creating new SDU segment. Tx SDU (%d B),,nof_bytes=%d B ", tx_sdu->N_bytes, nof_bytes); + // Sanity check: can this SDU be sent this in a single PDU? - if (tx_sdu->N_bytes + 2 >= nof_bytes) { - logger->error("Calling build_new_sdu_segment(), but there are enough bytes to tx in a single PDU."); - return SRSRAN_ERROR; + if ((tx_sdu->N_bytes + 2) < nof_bytes) { + logger->error("Calling build_new_sdu_segment(), but there are enough bytes to tx in a single PDU. Tx SDU (%d B), " + "nof_bytes=%d B ", + tx_sdu->N_bytes, + nof_bytes); + return 0; } // Sanity check: can this SDU be sent considering header overhead? - if (1 + 2 >= nof_bytes) { // Only two bytes, as SO is 0 - logger->error("Cannot build new sdu_segment, but there are not enough bytes to tx header plus data."); - return SRSRAN_ERROR; + if (3 < nof_bytes) { // Only two bytes of header, as SO is 0 + logger->error( + "Cannot build new sdu_segment, there are not enough bytes allocated to tx header plus data. nof_bytes=%d", + nof_bytes); + return 0; } // Prepare header @@ -201,12 +213,29 @@ int rlc_am_nr_tx::build_new_sdu_segment(const unique_byte_buffer_t& tx_sdu, log_rlc_am_nr_pdu_header_to_string(logger->info, hdr); // Write header - uint32_t len = rlc_am_nr_write_data_pdu_header(hdr, payload); - if (len > nof_bytes) { + uint32_t hdr_len = rlc_am_nr_write_data_pdu_header(hdr, payload); + if (hdr_len > nof_bytes) { logger->error("Error writing AMD PDU header"); } - return SRSRAN_SUCCESS; + uint32_t segment_payload_len = nof_bytes - hdr_len; + memcpy(&payload[hdr_len], tx_pdu.buf->msg, segment_payload_len); + return hdr_len + segment_payload_len; +} + +int rlc_am_nr_tx::build_continuation_sdu_segment(rlc_amd_tx_pdu_nr& tx_pdu, uint8_t* payload, uint32_t nof_bytes) +{ + logger->info("Continuing SDU segment. SN=%d, Tx SDU (%d B), nof_bytes=%d B ", + current_sdu.rlc_sn, + current_sdu.buf->N_bytes, + nof_bytes); + + // Can the rest of the SDU be sent on a single segment PDU? + + // Sanity check: can this SDU be sent considering header overhead? + + // Prepare header + return 0; } int rlc_am_nr_tx::build_retx_pdu(unique_byte_buffer_t& tx_pdu, uint32_t nof_bytes) diff --git a/lib/test/rlc/rlc_am_nr_test.cc b/lib/test/rlc/rlc_am_nr_test.cc index 0e9a28492..1c34af0ef 100644 --- a/lib/test/rlc/rlc_am_nr_test.cc +++ b/lib/test/rlc/rlc_am_nr_test.cc @@ -220,12 +220,10 @@ int lost_pdu_test() timer_handler timers(8); byte_buffer_t pdu_bufs[NBUFS]; - auto& test_logger = srslog::fetch_basic_logger("TESTER "); - test_logger.info("======================="); - test_logger.info("==== Lost PDU Test ===="); - test_logger.info("======================="); - 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); + auto& test_logger = srslog::fetch_basic_logger("TESTER "); + 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); + test_delimit_logger delimiter("lost PDU"); // before configuring entity TESTASSERT(0 == rlc1.get_buffer_state()); @@ -340,15 +338,13 @@ int lost_pdu_test() } /* - * Test the loss of a single PDU. - * NACK should be visible in the status report. - * Retx after NACK should be present too. + * Test the basic segmentation of a single SDU. + * A single SDU of 3 bytes is segmented into 3 PDUs */ int basic_segmentation_test() { rlc_am_tester tester; timer_handler timers(8); - byte_buffer_t pdu_bufs[NBUFS]; auto& test_logger = srslog::fetch_basic_logger("TESTER "); test_delimit_logger delimiter("basic segmentation"); rlc_am rlc1(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); @@ -365,14 +361,29 @@ int basic_segmentation_test() return -1; } - basic_test_tx(&rlc1, pdu_bufs); - - // Write 5 PDUs into RLC2 - for (int i = 0; i < NBUFS; i++) { - if (i != 3) { - rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); // Don't write RLC_SN=3. + // Push 1 SDU into RLC1 + unique_byte_buffer_t sdu; + sdu = srsran::make_byte_buffer(); + TESTASSERT(nullptr != sdu); + sdu->msg[0] = 0; // Write the index into the buffer + sdu->N_bytes = 3; // Give the SDU the size of 3 bytes + sdu->md.pdcp_sn = 0; // PDCP SN for notifications + rlc1.write_sdu(std::move(sdu)); + + // Read 3 PDUs + unique_byte_buffer_t pdu_bufs[3]; + for (int i = 0; i < 3; i++) { + pdu_bufs[i] = srsran::make_byte_buffer(); + TESTASSERT(nullptr != pdu_bufs[i]); + if (i == 0) { + pdu_bufs[i]->N_bytes = rlc1.read_pdu(pdu_bufs[i]->msg, 3); + TESTASSERT_EQ(3, pdu_bufs[i]->N_bytes); + } else { + pdu_bufs[i]->N_bytes = rlc1.read_pdu(pdu_bufs[i]->msg, 5); + TESTASSERT_EQ(5, pdu_bufs[i]->N_bytes); } } + return SRSRAN_SUCCESS; } @@ -404,6 +415,7 @@ int main(int argc, char** argv) TESTASSERT(window_checker_test() == SRSRAN_SUCCESS); TESTASSERT(basic_test() == SRSRAN_SUCCESS); TESTASSERT(lost_pdu_test() == SRSRAN_SUCCESS); + TESTASSERT(basic_segmentation_test() == SRSRAN_SUCCESS); return SRSRAN_SUCCESS; }