rlc, nr: Increment retx_count for segments

master
Robert Falkenberg 3 years ago
parent 034aa6a6d4
commit 511ad9ed25

@ -225,6 +225,7 @@ public:
rlc_cnfg.rat = srsran_rat_t::nr;
rlc_cnfg.rlc_mode = rlc_mode_t::am;
rlc_cnfg.am_nr.t_status_prohibit = 8;
rlc_cnfg.am_nr.max_retx_thresh = 4;
rlc_cnfg.am_nr.t_reassembly = 35;
rlc_cnfg.am_nr.poll_pdu = 4;
return rlc_cnfg;

@ -79,7 +79,6 @@ struct rlc_amd_tx_pdu_nr {
uint32_t retx_count = RETX_COUNT_NOT_STARTED;
struct pdu_segment {
uint32_t so = 0;
uint32_t retx_count = 0;
uint32_t payload_len = 0;
};
std::list<pdu_segment> segment_list;

@ -723,11 +723,13 @@ void rlc_am_nr_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes)
// Process N_acks
for (uint32_t nack_idx = 0; nack_idx < status.N_nack; nack_idx++) {
// TODO: Possibly loop NACK range
if (st.tx_next_ack <= status.nacks[nack_idx].nack_sn && status.nacks[nack_idx].nack_sn <= st.tx_next) {
auto nack = status.nacks[nack_idx];
uint32_t nack_sn = nack.nack_sn;
if (tx_window.has_sn(nack_sn)) {
auto& pdu = tx_window[nack_sn];
auto& pdu = tx_window[nack_sn];
bool retx_enqueued = false;
if (nack.has_so) {
// NACK'ing missing bytes in SDU segment.
@ -739,39 +741,45 @@ void rlc_am_nr_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes)
segm != pdu.segment_list.end();
segm++) {
if (segm->so >= nack.so_start && segm->so < nack.so_end) {
// TODO: Check if this segment is not already queued for retransmission
rlc_amd_retx_t& retx = retx_queue.push();
retx.sn = nack_sn;
retx.is_segment = true;
retx.so_start = segm->so;
retx.current_so = segm->so;
retx.so_end = segm->so + segm->payload_len;
retx_enqueued = true;
}
}
// TODO: Handle retx_count for segments
} else {
// NACK'ing full SDU.
// add to retx queue if it's not already there
if (not retx_queue.has_sn(nack_sn)) {
// Increment retx_count and inform upper layers if needed
if (pdu.retx_count == RETX_COUNT_NOT_STARTED) {
// Set retx_count = 0 on first RE-transmission (38.322 Sec. 5.3.2)
pdu.retx_count = 0;
} else {
// Increment otherwise
pdu.retx_count++;
}
check_sn_reached_max_retx(nack_sn);
rlc_amd_retx_t& retx = retx_queue.push();
retx.sn = nack_sn;
retx.is_segment = false;
retx.so_start = 0;
retx.current_so = 0;
retx.so_end = pdu.sdu_buf->N_bytes;
retx_enqueued = true;
}
}
if (retx_enqueued) {
// Increment retx_count
if (pdu.retx_count == RETX_COUNT_NOT_STARTED) {
// Set retx_count = 0 on first RE-transmission (38.322 Sec. 5.3.2)
pdu.retx_count = 0;
} else {
// Increment otherwise
pdu.retx_count++;
}
// Inform upper layers if needed
check_sn_reached_max_retx(nack_sn);
RlcInfo("Schedule SN=%d for retx", nack_sn);
}
}
}
}

@ -884,7 +884,8 @@ int retx_segment_test()
}
// This test checks whether RLC informs upper layer when max retransmission has been reached
int max_retx_test()
// due to lost SDUs as a whole
int max_retx_lost_sdu_test()
{
rlc_am_tester tester;
timer_handler timers(8);
@ -951,6 +952,75 @@ int max_retx_test()
return SRSRAN_SUCCESS;
}
// This test checks whether RLC informs upper layer when max retransmission has been reached
// due to lost SDU segments
int max_retx_lost_segments_test()
{
rlc_am_tester tester;
timer_handler timers(8);
int len = 0;
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);
srslog::fetch_basic_logger("RLC_AM_1").set_hex_dump_max_size(100);
srslog::fetch_basic_logger("RLC").set_hex_dump_max_size(100);
const rlc_config_t rlc_cfg = rlc_config_t::default_rlc_am_nr_config();
if (not rlc1.configure(rlc_cfg)) {
return SRSRAN_ERROR;
}
// Push 2 SDUs into RLC1
const uint32_t n_sdus = 2;
unique_byte_buffer_t sdu_bufs[n_sdus];
for (uint32_t i = 0; i < n_sdus; i++) {
sdu_bufs[i] = srsran::make_byte_buffer();
sdu_bufs[i]->msg[0] = i; // Write the index into the buffer
sdu_bufs[i]->N_bytes = 20; // Give each buffer a size of 20 bytes
sdu_bufs[i]->md.pdcp_sn = i; // PDCP SN for notifications
rlc1.write_sdu(std::move(sdu_bufs[i]));
}
// Read 4 PDUs from RLC1 (max 15 byte each)
const uint32_t n_pdus = 4;
byte_buffer_t pdu_bufs[n_pdus];
for (uint32_t i = 0; i < n_pdus; i++) {
len = rlc1.read_pdu(pdu_bufs[i].msg, 15); // 2 byte header + 13 byte payload
pdu_bufs[i].N_bytes = len;
}
TESTASSERT(0 == rlc1.get_buffer_state());
// Fake status PDU that ack SN=1 and nack SN=0
rlc_am_nr_status_pdu_t fake_status = {};
fake_status.ack_sn = 2; // delivered up to SN=1
fake_status.N_nack = 1; // one SN was lost
fake_status.nacks[0].nack_sn = 0; // it was SN=0 that was lost
// pack into PDU
byte_buffer_t status_pdu;
rlc_am_nr_write_status_pdu(fake_status, rlc_cfg.am_nr.tx_sn_field_length, &status_pdu);
// Exceed the number of tolerated retransmissions by one additional retransmission
// to trigger notification of the higher protocol layers. Note that the initial transmission
// (before starting retransmissions) does not count. See TS 38.322 Sec. 5.3.2
for (uint32_t retx_count = 0; retx_count < rlc_cfg.am_nr.max_retx_thresh + 1; ++retx_count) {
// we've not yet reached max attempts
TESTASSERT(tester.max_retx_triggered == false);
// Write status PDU to RLC1
rlc1.write_pdu(status_pdu.msg, status_pdu.N_bytes);
byte_buffer_t pdu_buf;
len = rlc1.read_pdu(pdu_buf.msg, 3); // 2 byte header + 1 byte payload
}
// Now maxRetx should have been triggered
TESTASSERT(tester.max_retx_triggered == true);
return SRSRAN_SUCCESS;
}
// This test checks the correct functioning of RLC discard functionality
int discard_test()
{
@ -1084,7 +1154,8 @@ int main()
TESTASSERT(basic_segmentation_test() == SRSRAN_SUCCESS);
TESTASSERT(segment_retx_test() == SRSRAN_SUCCESS);
TESTASSERT(retx_segment_test() == SRSRAN_SUCCESS);
TESTASSERT(max_retx_test() == SRSRAN_SUCCESS);
TESTASSERT(max_retx_lost_sdu_test() == SRSRAN_SUCCESS);
TESTASSERT(max_retx_lost_segments_test() == SRSRAN_SUCCESS);
TESTASSERT(discard_test() == SRSRAN_SUCCESS);
return SRSRAN_SUCCESS;
}

Loading…
Cancel
Save