diff --git a/lib/src/upper/rlc_am_lte.cc b/lib/src/upper/rlc_am_lte.cc index 320f95d48..be6ca2cdb 100644 --- a/lib/src/upper/rlc_am_lte.cc +++ b/lib/src/upper/rlc_am_lte.cc @@ -1049,8 +1049,8 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no if (tx_window.count(i) > 0) { it = tx_window.find(i); if (it != tx_window.end()) { + update_notification_ack_info(it->second, notify_info_vec); if (update_vt_a) { - update_notification_ack_info(it->second, notify_info_vec); tx_window.erase(it); vt_a = (vt_a + 1) % MOD; vt_ms = (vt_ms + 1) % MOD; @@ -1079,13 +1079,18 @@ void rlc_am_lte::rlc_am_lte_tx::update_notification_ack_info(const rlc_amd_tx_pd std::vector& notify_info_vec) { // Notify PDCP of the number of bytes succesfully delivered - uint32_t notified_bytes = 0; - uint32_t nof_bytes = 0; - uint32_t pdcp_sn = 0; + uint32_t total_acked_bytes = 0; + uint32_t nof_bytes = 0; + uint32_t pdcp_sn = 0; for (uint32_t pdcp_notify_it = 0; pdcp_notify_it < tx_pdu.header.N_li; pdcp_notify_it++) { nof_bytes = tx_pdu.header.li[pdcp_notify_it]; pdcp_sn = tx_pdu.pdcp_tx_counts[pdcp_notify_it]; + if (undelivered_sdu_info_queue.find(pdcp_sn) == undelivered_sdu_info_queue.end()) { + log->debug("Could not find notification info, perhaps SDU was already ACK'ed.\n"); + continue; + } undelivered_sdu_info_queue[pdcp_sn].acked_bytes += nof_bytes; + total_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); @@ -1093,7 +1098,11 @@ void rlc_am_lte::rlc_am_lte_tx::update_notification_ack_info(const rlc_amd_tx_pd } } pdcp_sn = tx_pdu.pdcp_tx_counts[tx_pdu.header.N_li]; - nof_bytes = tx_pdu.buf->N_bytes - notified_bytes; // Notify last SDU + nof_bytes = tx_pdu.buf->N_bytes - total_acked_bytes; // Notify last SDU + if (undelivered_sdu_info_queue.find(pdcp_sn) == undelivered_sdu_info_queue.end()) { + log->debug("Could not find notification info, perhaps SDU was already ACK'ed.\n"); + return; + } 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); @@ -1438,7 +1447,6 @@ void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu_segment(uint8_t* pa // Check if we already have a segment from the same PDU it = rx_segments.find(header.sn); if (rx_segments.end() != it) { - if (header.p) { log->info("%s Status packet requested through polling bit\n", RB_NAME); do_status = true; @@ -1451,7 +1459,6 @@ void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu_segment(uint8_t* pa } } else { - // Create new PDU segment list and write to rx_segments rlc_amd_rx_pdu_segments_t pdu; pdu.segments.push_back(std::move(segment)); diff --git a/lib/test/upper/rlc_am_notify_pdcp_test.cc b/lib/test/upper/rlc_am_notify_pdcp_test.cc index 6c63ed249..e67aa3ca7 100644 --- a/lib/test/upper/rlc_am_notify_pdcp_test.cc +++ b/lib/test/upper/rlc_am_notify_pdcp_test.cc @@ -34,8 +34,6 @@ public: } 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; } } }; @@ -141,6 +139,7 @@ int two_pdus_notify_test() 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(pdcp.notified_counts.size() == 0); // Feed ack of PDU2 to RLC srslte::rlc_status_pdu_t s2; @@ -403,10 +402,14 @@ int two_sdus_out_of_order_ack_notify_test() // Intentionally do not write first ack to RLC - // Feed ack of PDU2 to RLC + // Ack of PDU2 to RLC, with PDU1 with NACK + srslte::rlc_status_nack_t nack = {}; + nack.nack_sn = 1; + srslte::rlc_status_pdu_t s2; - s2.ack_sn = 2; - s2.N_nack = 0; + s2.ack_sn = 2; + s2.N_nack = 1; + s2.nacks[0] = nack; // Write second ack sta_buf->N_bytes = srslte::rlc_am_write_status_pdu(&s2, sta_buf->msg); @@ -472,6 +475,7 @@ int two_pdus_out_of_order_ack_notify_test() 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(pdcp.notified_counts.size() == 0); // Feed ack of PDU2 to RLC srslte::rlc_status_pdu_t s2; diff --git a/lib/test/upper/rlc_am_test.cc b/lib/test/upper/rlc_am_test.cc index aa8aeecc5..823f6b868 100644 --- a/lib/test/upper/rlc_am_test.cc +++ b/lib/test/upper/rlc_am_test.cc @@ -57,7 +57,16 @@ 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) {} + 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; + } + } // RRC interface void max_retx_attempted() {} @@ -66,6 +75,8 @@ public: unique_byte_buffer_t sdus[10]; int n_sdus; rlc_pcap* pcap; + + std::map notified_counts; // Map of PDCP SNs to number of notifications }; class ul_writer : public thread @@ -114,14 +125,14 @@ private: int basic_test_tx(rlc_am_lte* rlc, byte_buffer_t pdu_bufs[NBUFS]) { - // Push 5 SDUs into RLC1 byte_buffer_pool* pool = byte_buffer_pool::get_instance(); unique_byte_buffer_t sdu_bufs[NBUFS]; for (int i = 0; i < NBUFS; i++) { - sdu_bufs[i] = srslte::allocate_unique_buffer(*pool, true); - sdu_bufs[i]->msg[0] = i; // Write the index into the buffer - sdu_bufs[i]->N_bytes = 1; // Give each buffer a size of 1 byte + sdu_bufs[i] = srslte::allocate_unique_buffer(*pool, true); + sdu_bufs[i]->msg[0] = i; // Write the index into the buffer + sdu_bufs[i]->N_bytes = 1; // Give each buffer a size of 1 byte + sdu_bufs[i]->md.pdcp_sn = i; // PDCP SN for notifications rlc->write_sdu(std::move(sdu_bufs[i])); } @@ -182,9 +193,13 @@ int basic_test() // Write status PDU to RLC1 rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); - for (int i = 0; i < tester.n_sdus; i++) { + // Check PDCP notifications + std::cout << tester.notified_counts.size() << std::endl; + TESTASSERT(tester.notified_counts.size() == 5); + for (uint16_t i = 0; i < tester.n_sdus; i++) { TESTASSERT(tester.sdus[i]->N_bytes == 1); TESTASSERT(*(tester.sdus[i]->msg) == i); + TESTASSERT(tester.notified_counts[i] == 1); } // Check statistics @@ -213,9 +228,10 @@ int concat_test() byte_buffer_pool* pool = byte_buffer_pool::get_instance(); unique_byte_buffer_t sdu_bufs[NBUFS]; for (int i = 0; i < NBUFS; i++) { - sdu_bufs[i] = srslte::allocate_unique_buffer(*pool, true); - sdu_bufs[i]->msg[0] = i; // Write the index into the buffer - sdu_bufs[i]->N_bytes = 1; // Give each buffer a size of 1 byte + sdu_bufs[i] = srslte::allocate_unique_buffer(*pool, true); + sdu_bufs[i]->msg[0] = i; // Write the index into the buffer + sdu_bufs[i]->N_bytes = 1; // Give each buffer a size of 1 byte + sdu_bufs[i]->md.pdcp_sn = i; // PDCP SN for notifications rlc1.write_sdu(std::move(sdu_bufs[i])); } @@ -253,6 +269,14 @@ int concat_test() TESTASSERT(*(tester.sdus[i]->msg) == i); } + // Check PDCP notifications + TESTASSERT(tester.notified_counts.size() == 5); + for (uint16_t i = 0; i < tester.n_sdus; i++) { + TESTASSERT(tester.sdus[i]->N_bytes == 1); + TESTASSERT(*(tester.sdus[i]->msg) == i); + TESTASSERT(tester.notified_counts[i] == 1); + } + // Check statistics TESTASSERT(rx_is_tx(rlc1.get_metrics(), rlc2.get_metrics())); @@ -283,7 +307,8 @@ int segment_test(bool in_seq_rx) sdu_bufs[i] = srslte::allocate_unique_buffer(*pool, true); for (int j = 0; j < 10; j++) sdu_bufs[i]->msg[j] = j; - sdu_bufs[i]->N_bytes = 10; // Give each buffer a size of 10 bytes + sdu_bufs[i]->N_bytes = 10; // Give each buffer a size of 10 bytes + sdu_bufs[i]->md.pdcp_sn = i; // PDCP SN for notifications rlc1.write_sdu(std::move(sdu_bufs[i])); } @@ -329,6 +354,13 @@ int segment_test(bool in_seq_rx) // Write status PDU to RLC1 rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); + + // Check all notification of ack'ed PDUs + TESTASSERT(tester.notified_counts.size() == 5); + for (int i = 0; i < NBUFS; i++) { + auto not_it = tester.notified_counts.find(i); + TESTASSERT(not_it != tester.notified_counts.end() && tester.notified_counts[i] == 1); + } } TESTASSERT(0 == rlc2.get_buffer_state()); @@ -367,9 +399,10 @@ int retx_test() byte_buffer_pool* pool = byte_buffer_pool::get_instance(); unique_byte_buffer_t sdu_bufs[NBUFS]; for (int i = 0; i < NBUFS; i++) { - sdu_bufs[i] = srslte::allocate_unique_buffer(*pool, true); - sdu_bufs[i]->msg[0] = i; // Write the index into the buffer - sdu_bufs[i]->N_bytes = 1; // Give each buffer a size of 1 byte + sdu_bufs[i] = srslte::allocate_unique_buffer(*pool, true); + sdu_bufs[i]->msg[0] = i; // Write the index into the buffer + sdu_bufs[i]->N_bytes = 1; // Give each buffer a size of 1 byte + sdu_bufs[i]->md.pdcp_sn = i; // PDCP SN for notifications rlc1.write_sdu(std::move(sdu_bufs[i])); } @@ -422,6 +455,17 @@ int retx_test() TESTASSERT(3 == rlc1.get_buffer_state()); // 2 byte header + 1 byte payload + // Check notifications of ack'ed PDUs + TESTASSERT(tester.notified_counts.size() == 4); + for (int i = 0; i < NBUFS; i++) { + auto not_it = tester.notified_counts.find(i); + if (i != 1) { + TESTASSERT(not_it != tester.notified_counts.end() && tester.notified_counts[i] == 1); + } else { + TESTASSERT(not_it == tester.notified_counts.end()); + } + } + // Read the retx PDU from RLC1 byte_buffer_t retx; len = rlc1.read_pdu(retx.msg, 3); // 2 byte header + 1 byte payload @@ -438,6 +482,33 @@ int retx_test() return -1; } + // Step timers until poll Retx timeout expires + for (int cnt = 0; cnt < 5; cnt++) { + timers.step_all(); + } + + // Get status report of RETX PDU + buffer_state = rlc2.get_buffer_state(); + TESTASSERT(2 == buffer_state); + len = rlc2.read_pdu(status_buf.msg, buffer_state); // provide exactly the reported buffer state + status_buf.N_bytes = len; + + // Assert status is correct + status_check = {}; + rlc_am_read_status_pdu(status_buf.msg, status_buf.N_bytes, &status_check); + TESTASSERT(status_check.N_nack == 0); // 1 packet was lost. + TESTASSERT(status_check.ack_sn == 5); // Delivered up to SN 4. + + // Write status PDU to RLC1 + rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); + + // Check all notification of ack'ed PDUs + TESTASSERT(tester.notified_counts.size() == 5); + for (int i = 0; i < NBUFS; i++) { + auto not_it = tester.notified_counts.find(i); + TESTASSERT(not_it != tester.notified_counts.end() && tester.notified_counts[i] == 1); + } + return 0; } @@ -482,8 +553,7 @@ int segment_retx_test() TESTASSERT(rlc1.get_buffer_state() == 0); // Step timers until poll Retx timeout expires - int cnt = 5; - while (cnt--) { + for (int cnt = 0; cnt < 5; cnt++) { timers.step_all(); } @@ -506,12 +576,20 @@ int segment_retx_test() len = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status status_buf.N_bytes = len; + // Assert status is correct + rlc_status_pdu_t status_check = {}; + rlc_am_read_status_pdu(status_buf.msg, status_buf.N_bytes, &status_check); + TESTASSERT(status_check.N_nack == 0); // 1 packet was lost. + TESTASSERT(status_check.ack_sn == 1); // Delivered up to SN 0. + // Write status PDU to RLC1 rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); + // Make sure no notifications yet + TESTASSERT(tester.notified_counts.size() == 0); + // Step timers again until poll Retx timeout expires - cnt = 5; - while (cnt--) { + for (int cnt = 0; cnt < 5; cnt++) { timers.step_all(); } @@ -532,6 +610,16 @@ int segment_retx_test() status_buf.N_bytes = len; rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); + // Assert status is correct + status_check = {}; + rlc_am_read_status_pdu(status_buf.msg, status_buf.N_bytes, &status_check); + TESTASSERT(status_check.N_nack == 0); // 1 packet was lost. + TESTASSERT(status_check.ack_sn == 2); // Delivered up to SN 0. + + // Make sure SDU was notified + TESTASSERT(tester.notified_counts.size() == 1); + TESTASSERT(tester.notified_counts.find(0) != tester.notified_counts.end() && tester.notified_counts[0] == 1); + TESTASSERT(tester.n_sdus == nof_sdus); for (int i = 0; i < tester.n_sdus; i++) { if (tester.sdus[i]->N_bytes != 10) { @@ -573,7 +661,8 @@ int resegment_test_1() sdu_bufs[i] = srslte::allocate_unique_buffer(*pool, true); for (int j = 0; j < 10; j++) sdu_bufs[i]->msg[j] = j; - sdu_bufs[i]->N_bytes = 10; // Give each buffer a size of 10 bytes + sdu_bufs[i]->N_bytes = 10; // Give each buffer a size of 10 bytes + sdu_bufs[i]->md.pdcp_sn = i; rlc1.write_sdu(std::move(sdu_bufs[i])); } @@ -595,8 +684,7 @@ int resegment_test_1() } // Step timers until reordering timeout expires - int cnt = 5; - while (cnt--) { + for (int cnt = 0; cnt < 5; cnt++) { timers.step_all(); } @@ -607,11 +695,29 @@ int resegment_test_1() len = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status status_buf.N_bytes = len; + // Assert status is correct + rlc_status_pdu_t status_check = {}; + rlc_am_read_status_pdu(status_buf.msg, status_buf.N_bytes, &status_check); + TESTASSERT(status_check.N_nack == 1); // 1 packet was lost. + TESTASSERT(status_check.ack_sn == 5); // Delivered up to SN 5. + // Write status PDU to RLC1 rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); TESTASSERT(12 == rlc1.get_buffer_state()); // 2 byte header + 10 data + // Check notifications + rrc_log1->debug("%ld\n", tester.notified_counts.size()); + TESTASSERT(tester.notified_counts.size() == 4); + for (int i = 0; i < 5; i++) { + auto it = tester.notified_counts.find(i); + if (i != 1) { + TESTASSERT(it != tester.notified_counts.end() && tester.notified_counts[i] == 1); + } else { + TESTASSERT(it == tester.notified_counts.end()); + } + } + // Read the retx PDU from RLC1 and force resegmentation byte_buffer_t retx1; len = rlc1.read_pdu(retx1.msg, 9); // 4 byte header + 5 data @@ -622,6 +728,22 @@ int resegment_test_1() TESTASSERT(9 == rlc1.get_buffer_state()); + // Step timers to get status report + for (int cnt = 0; cnt < 5; cnt++) { + timers.step_all(); + } + + // Read status PDU from RLC2 + status_buf = {}; + len = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status + status_buf.N_bytes = len; + + // Assert status is correct + status_check = {}; + rlc_am_read_status_pdu(status_buf.msg, status_buf.N_bytes, &status_check); + TESTASSERT(status_check.N_nack == 1); // 1 packet was lost. + TESTASSERT(status_check.ack_sn == 5); // Delivered up to SN 5. + // Read the remaining segment byte_buffer_t retx2; len = rlc1.read_pdu(retx2.msg, 9); // 4 byte header + 5 data @@ -639,12 +761,37 @@ int resegment_test_1() return -1; } + // Step timers to get status report + for (int cnt = 0; cnt < 5; cnt++) { + timers.step_all(); + } + + // Read status PDU from RLC2 + status_buf = {}; + len = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status + status_buf.N_bytes = len; + + // Assert status is correct + status_check = {}; + rlc_am_read_status_pdu(status_buf.msg, status_buf.N_bytes, &status_check); + TESTASSERT(status_check.N_nack == 0); // all packets delivered. + TESTASSERT(status_check.ack_sn == 5); // Delivered up to SN 5. + + // Write status PDU to RLC1 + rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); + + // Check notifications + TESTASSERT(tester.notified_counts.size() == 5); + for (int i = 0; i < 5; i++) { + auto it = tester.notified_counts.find(i); + TESTASSERT(it != tester.notified_counts.end() && tester.notified_counts[i] == 1); + } + return 0; } int resegment_test_2() { - // SDUs: | 10 | 10 | 10 | 10 | 10 | // PDUs: | 5 | 10 | 20 | 10 | 5 | // Retx PDU segments: | 10 | 10 | @@ -671,7 +818,8 @@ int resegment_test_2() sdu_bufs[i] = srslte::allocate_unique_buffer(*pool, true); for (int j = 0; j < 10; j++) sdu_bufs[i]->msg[j] = j; - sdu_bufs[i]->N_bytes = 10; // Give each buffer a size of 10 bytes + sdu_bufs[i]->N_bytes = 10; // Give each buffer a size of 10 bytes + sdu_bufs[i]->md.pdcp_sn = i; // Give each buffer a size of 10 bytes rlc1.write_sdu(std::move(sdu_bufs[i])); } @@ -694,8 +842,7 @@ int resegment_test_2() } // Step timers until reordering timeout expires - int cnt = 5; - while (cnt--) { + for (int cnt = 0; cnt < 5; cnt++) { timers.step_all(); } @@ -705,11 +852,28 @@ int resegment_test_2() byte_buffer_t status_buf; status_buf.N_bytes = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status + // Assert status is correct + rlc_status_pdu_t status_check = {}; + rlc_am_read_status_pdu(status_buf.msg, status_buf.N_bytes, &status_check); + TESTASSERT(status_check.N_nack == 1); // all packets delivered. + TESTASSERT(status_check.ack_sn == 5); // Delivered up to SN 5. + // Write status PDU to RLC1 rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); TESTASSERT(25 == rlc1.get_buffer_state()); // 4 byte header + 20 data + // Check notifications + TESTASSERT(tester.notified_counts.size() == 2); + for (int i = 0; i < 5; i++) { + auto it = tester.notified_counts.find(i); + if (i == 0 || i == 4) { + TESTASSERT(it != tester.notified_counts.end() && tester.notified_counts[i] == 1); + } else { + TESTASSERT(it == tester.notified_counts.end()); + } + } + // Read the retx PDU from RLC1 and force resegmentation byte_buffer_t retx1; retx1.N_bytes = rlc1.read_pdu(retx1.msg, 16); // 6 byte header + 10 data @@ -735,12 +899,33 @@ int resegment_test_2() return -1; } + // Step timers until reordering timeout expires + for (int cnt = 0; cnt < 5; cnt++) { + timers.step_all(); + } + + // Read status PDU from RLC2 + status_buf.N_bytes = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status + + // Assert status is correct + status_check = {}; + rlc_am_read_status_pdu(status_buf.msg, status_buf.N_bytes, &status_check); + TESTASSERT(status_check.N_nack == 0); // all packets delivered. + TESTASSERT(status_check.ack_sn == 5); // Delivered up to SN 5. + + // Write status PDU to RLC1 + rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); + TESTASSERT(tester.notified_counts.size() == 5); + + for (int i = 0; i < 5; i++) { + auto it = tester.notified_counts.find(i); + TESTASSERT(it != tester.notified_counts.end() && tester.notified_counts[i] == 1); + } return 0; } int resegment_test_3() { - // SDUs: | 10 | 10 | 10 | 10 | 10 | // PDUs: | 5 | 5| 20 | 10 | 10 | // Retx PDU segments: | 10 | 10 | @@ -766,7 +951,8 @@ int resegment_test_3() sdu_bufs[i] = srslte::allocate_unique_buffer(*pool, true); for (int j = 0; j < 10; j++) sdu_bufs[i]->msg[j] = j; - sdu_bufs[i]->N_bytes = 10; // Give each buffer a size of 10 bytes + sdu_bufs[i]->N_bytes = 10; // Give each buffer a size of 10 bytes + sdu_bufs[i]->md.pdcp_sn = i; rlc1.write_sdu(std::move(sdu_bufs[i])); } @@ -789,8 +975,7 @@ int resegment_test_3() } // Step timers until reordering timeout expires - int cnt = 5; - while (cnt--) { + for (int cnt = 0; cnt < 5; cnt++) { timers.step_all(); } @@ -800,9 +985,26 @@ int resegment_test_3() byte_buffer_t status_buf; status_buf.N_bytes = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status + // Assert status is correct + rlc_status_pdu_t status_check = {}; + rlc_am_read_status_pdu(status_buf.msg, status_buf.N_bytes, &status_check); + TESTASSERT(status_check.N_nack == 1); // all packets delivered. + TESTASSERT(status_check.ack_sn == 5); // Delivered up to SN 5. + // Write status PDU to RLC1 rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); + // Check notifications + TESTASSERT(tester.notified_counts.size() == 3); + for (int i = 0; i < 5; i++) { + auto it = tester.notified_counts.find(i); + if (i == 0 || i == 3 || i == 4) { + TESTASSERT(it != tester.notified_counts.end() && tester.notified_counts[i] == 1); + } else { + TESTASSERT(it == tester.notified_counts.end()); + } + } + // Read the retx PDU from RLC1 and force resegmentation byte_buffer_t retx1; retx1.N_bytes = rlc1.read_pdu(retx1.msg, 16); // 6 byte header + 10 data @@ -826,6 +1028,29 @@ int resegment_test_3() return -1; } + // Get status from RLC 2 + for (int cnt = 0; cnt < 5; cnt++) { + timers.step_all(); + } + + // Read status PDU from RLC2 + status_buf.N_bytes = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status + + // Assert status is correct + status_check = {}; + rlc_am_read_status_pdu(status_buf.msg, status_buf.N_bytes, &status_check); + TESTASSERT(status_check.N_nack == 0); // all packets delivered. + TESTASSERT(status_check.ack_sn == 5); // Delivered up to SN 5. + + // Write status PDU to RLC1 + rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); + + // Check final notifications + TESTASSERT(tester.notified_counts.size() == 5); + for (int i = 0; i < 5; i++) { + auto it = tester.notified_counts.find(i); + TESTASSERT(it != tester.notified_counts.end() && tester.notified_counts[i] == 1); + } return 0; } @@ -856,7 +1081,8 @@ int resegment_test_4() sdu_bufs[i] = srslte::allocate_unique_buffer(*pool, true); for (int j = 0; j < 10; j++) sdu_bufs[i]->msg[j] = j; - sdu_bufs[i]->N_bytes = 10; // Give each buffer a size of 10 bytes + sdu_bufs[i]->N_bytes = 10; // Give each buffer a size of 10 bytes + sdu_bufs[i]->md.pdcp_sn = i; rlc1.write_sdu(std::move(sdu_bufs[i])); } @@ -890,9 +1116,25 @@ int resegment_test_4() byte_buffer_t status_buf; status_buf.N_bytes = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status + // Assert status is correct + rlc_status_pdu_t status_check = {}; + rlc_am_read_status_pdu(status_buf.msg, status_buf.N_bytes, &status_check); + TESTASSERT(status_check.N_nack == 1); // all packets delivered. + TESTASSERT(status_check.ack_sn == 5); // Delivered up to SN 5. + // Write status PDU to RLC1 rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); + TESTASSERT(tester.notified_counts.size() == 2); + for (int i = 0; i < 5; i++) { + auto it = tester.notified_counts.find(i); + if (i == 0 || i == 4) { + TESTASSERT(it != tester.notified_counts.end() && tester.notified_counts[i] == 1); + } else { + TESTASSERT(it == tester.notified_counts.end()); + } + } + // Read the retx PDU from RLC1 and force resegmentation byte_buffer_t retx1; retx1.N_bytes = rlc1.read_pdu(retx1.msg, 21); // 6 byte header + 15 data @@ -918,6 +1160,29 @@ int resegment_test_4() return -1; } + // Get status from RLC 2 + for (int cnt = 0; cnt < 5; cnt++) { + timers.step_all(); + } + + // Read status PDU from RLC2 + status_buf.N_bytes = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status + + // Assert status is correct + status_check = {}; + rlc_am_read_status_pdu(status_buf.msg, status_buf.N_bytes, &status_check); + TESTASSERT(status_check.N_nack == 0); // all packets delivered. + TESTASSERT(status_check.ack_sn == 5); // Delivered up to SN 5. + + // Write status PDU to RLC1 + rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); + + // Check final notifications + TESTASSERT(tester.notified_counts.size() == 5); + for (int i = 0; i < 5; i++) { + auto it = tester.notified_counts.find(i); + TESTASSERT(it != tester.notified_counts.end() && tester.notified_counts[i] == 1); + } return 0; } @@ -948,7 +1213,8 @@ int resegment_test_5() sdu_bufs[i] = srslte::allocate_unique_buffer(*pool, true); for (int j = 0; j < 10; j++) sdu_bufs[i]->msg[j] = j; - sdu_bufs[i]->N_bytes = 10; // Give each buffer a size of 10 bytes + sdu_bufs[i]->N_bytes = 10; // Give each buffer a size of 10 bytes + sdu_bufs[i]->md.pdcp_sn = i; rlc1.write_sdu(std::move(sdu_bufs[i])); } @@ -982,9 +1248,18 @@ int resegment_test_5() byte_buffer_t status_buf; status_buf.N_bytes = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status + // Assert status is correct + rlc_status_pdu_t status_check = {}; + rlc_am_read_status_pdu(status_buf.msg, status_buf.N_bytes, &status_check); + TESTASSERT(status_check.N_nack == 1); // all packets delivered. + TESTASSERT(status_check.ack_sn == 5); // Delivered up to SN 5. + // Write status PDU to RLC1 rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); + // Check notifications + TESTASSERT(tester.notified_counts.size() == 0); + // Read the retx PDU from RLC1 and force resegmentation byte_buffer_t retx1; retx1.N_bytes = rlc1.read_pdu(retx1.msg, 27); // 7 byte header + 20 data @@ -1010,6 +1285,30 @@ int resegment_test_5() return -1; } + // Get status from RLC 2 + for (int cnt = 0; cnt < 5; cnt++) { + timers.step_all(); + } + + // Read status PDU from RLC2 + status_buf.N_bytes = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status + + // Assert status is correct + status_check = {}; + rlc_am_read_status_pdu(status_buf.msg, status_buf.N_bytes, &status_check); + TESTASSERT(status_check.N_nack == 0); // all packets delivered. + TESTASSERT(status_check.ack_sn == 5); // Delivered up to SN 5. + + // Write status PDU to RLC1 + rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); + + // Check final notifications + TESTASSERT(tester.notified_counts.size() == 5); + for (int i = 0; i < 5; i++) { + auto it = tester.notified_counts.find(i); + TESTASSERT(it != tester.notified_counts.end() && tester.notified_counts[i] == 1); + } + return 0; } @@ -1041,14 +1340,16 @@ int resegment_test_6() sdu_bufs[i] = srslte::allocate_unique_buffer(*pool, true); for (int j = 0; j < 10; j++) sdu_bufs[i]->msg[j] = j; - sdu_bufs[i]->N_bytes = 10; // Give each buffer a size of 10 bytes + sdu_bufs[i]->N_bytes = 10; // Give each buffer a size of 10 bytes + sdu_bufs[i]->md.pdcp_sn = i; rlc1.write_sdu(std::move(sdu_bufs[i])); } for (int i = 3; i < 9; i++) { sdu_bufs[i] = srslte::allocate_unique_buffer(*pool, true); for (int j = 0; j < 54; j++) sdu_bufs[i]->msg[j] = j; - sdu_bufs[i]->N_bytes = 54; + sdu_bufs[i]->N_bytes = 54; + sdu_bufs[i]->md.pdcp_sn = i; rlc1.write_sdu(std::move(sdu_bufs[i])); } @@ -1086,11 +1387,28 @@ int resegment_test_6() len = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status status_buf.N_bytes = len; + // Assert status is correct + rlc_status_pdu_t status_check = {}; + rlc_am_read_status_pdu(status_buf.msg, status_buf.N_bytes, &status_check); + TESTASSERT(status_check.N_nack == 1); + TESTASSERT(status_check.ack_sn == 5); + // Write status PDU to RLC1 rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); TESTASSERT(278 == rlc1.get_buffer_state()); + // Check notifications + TESTASSERT(tester.notified_counts.size() == 4); + for (int i = 0; i < 5; i++) { + auto it = tester.notified_counts.find(i); + if (i == 0 || i == 1 || i == 2 || i == 8) { + TESTASSERT(it != tester.notified_counts.end() && tester.notified_counts[i] == 1); + } else { + TESTASSERT(it == tester.notified_counts.end()); + } + } + // Read the retx PDU from RLC1 and force resegmentation byte_buffer_t retx1; len = rlc1.read_pdu(retx1.msg, 129); @@ -1126,6 +1444,30 @@ int resegment_test_6() } } + // Get status from RLC 2 + for (int cnt = 0; cnt < 5; cnt++) { + timers.step_all(); + } + + // Read status PDU from RLC2 + status_buf.N_bytes = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status + + // Assert status is correct + status_check = {}; + rlc_am_read_status_pdu(status_buf.msg, status_buf.N_bytes, &status_check); + TESTASSERT(status_check.N_nack == 0); // all packets delivered. + TESTASSERT(status_check.ack_sn == 5); // Delivered up to SN 5. + + // Write status PDU to RLC1 + rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); + + // Check final notifications + TESTASSERT(tester.notified_counts.size() == 9); + for (int i = 0; i < 9; i++) { + auto it = tester.notified_counts.find(i); + TESTASSERT(it != tester.notified_counts.end() && tester.notified_counts[i] == 1); + } + return 0; } @@ -1169,7 +1511,8 @@ int resegment_test_7() for (uint32_t j = 0; j < sdu_size; j++) { sdu_bufs[i]->msg[j] = i; } - sdu_bufs[i]->N_bytes = sdu_size; // Give each buffer a size of 15 bytes + sdu_bufs[i]->N_bytes = sdu_size; // Give each buffer a size of 15 bytes + sdu_bufs[i]->md.pdcp_sn = i; rlc1.write_sdu(std::move(sdu_bufs[i])); } @@ -1231,6 +1574,12 @@ int resegment_test_7() byte_buffer_t status_buf; status_buf.N_bytes = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status + // Assert status is correct + rlc_status_pdu_t status_check = {}; + rlc_am_read_status_pdu(status_buf.msg, status_buf.N_bytes, &status_check); + TESTASSERT(status_check.N_nack == 1); // all packets delivered. + TESTASSERT(status_check.ack_sn == 5); // Delivered up to SN 5. + // Write status PDU to RLC1 rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); #if HAVE_PCAP @@ -1239,6 +1588,9 @@ int resegment_test_7() TESTASSERT(15 == rlc1.get_buffer_state()); + // Check notifications + TESTASSERT(tester.notified_counts.size() == 0); + // second round of retx, forcing resegmentation byte_buffer_t retx2[4]; for (uint32_t i = 0; i < 4; i++) { @@ -1265,6 +1617,12 @@ int resegment_test_7() TESTASSERT(rlc2.get_buffer_state()); status_buf.N_bytes = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status + // Assert status is correct + status_check = {}; + rlc_am_read_status_pdu(status_buf.msg, status_buf.N_bytes, &status_check); + TESTASSERT(status_check.N_nack == 0); // all packets delivered. + TESTASSERT(status_check.ack_sn == 5); // Delivered up to SN 5. + // Write status PDU to RLC1 rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); #if HAVE_PCAP @@ -1286,6 +1644,13 @@ int resegment_test_7() } } + // Check final notifications + TESTASSERT(tester.notified_counts.size() == 2); + for (int i = 0; i < 2; i++) { + auto it = tester.notified_counts.find(i); + TESTASSERT(it != tester.notified_counts.end() && tester.notified_counts[i] == 1); + } + #if HAVE_PCAP pcap.close(); #endif @@ -1333,7 +1698,8 @@ int resegment_test_8() for (uint32_t j = 0; j < sdu_size; j++) { sdu_bufs[i]->msg[j] = i; } - sdu_bufs[i]->N_bytes = sdu_size; // Give each buffer a size of 15 bytes + sdu_bufs[i]->N_bytes = sdu_size; // Give each buffer a size of 30 bytes + sdu_bufs[i]->md.pdcp_sn = i; rlc1.write_sdu(std::move(sdu_bufs[i])); }