mirror of https://github.com/PentHertz/srsLTE.git
rlc, nr: inform upper layer when max retransmissions is exceeded
This commit is contained in:
parent
0c0642c289
commit
034aa6a6d4
|
@ -76,7 +76,7 @@ struct rlc_amd_tx_pdu_nr {
|
|||
uint32_t pdcp_sn = INVALID_RLC_SN;
|
||||
rlc_am_nr_pdu_header_t header = {};
|
||||
unique_byte_buffer_t sdu_buf = nullptr;
|
||||
uint32_t retx_count = 0;
|
||||
uint32_t retx_count = RETX_COUNT_NOT_STARTED;
|
||||
struct pdu_segment {
|
||||
uint32_t so = 0;
|
||||
uint32_t retx_count = 0;
|
||||
|
@ -135,6 +135,7 @@ private:
|
|||
|
||||
uint32_t mod_nr = 4096;
|
||||
inline uint32_t tx_mod_base_nr(uint32_t sn) const;
|
||||
void check_sn_reached_max_retx(uint32_t sn);
|
||||
|
||||
/****************************************************************************
|
||||
* Configurable parameters
|
||||
|
|
|
@ -22,6 +22,7 @@ namespace srsran {
|
|||
const uint32_t RLC_AM_NR_WINDOW_SIZE_12BIT = 4096;
|
||||
const uint32_t RLC_AM_NR_WINDOW_SIZE_18BIT = 262144;
|
||||
const uint32_t INVALID_RLC_SN = 0xFFFFFFFF;
|
||||
const uint32_t RETX_COUNT_NOT_STARTED = 0xFFFFFFFF;
|
||||
|
||||
///< AM NR PDU header
|
||||
struct rlc_am_nr_pdu_header_t {
|
||||
|
|
|
@ -747,14 +747,23 @@ void rlc_am_nr_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes)
|
|||
retx.so_end = segm->so + segm->payload_len;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 counter and inform upper layers if needed
|
||||
pdu.retx_count++;
|
||||
// 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);
|
||||
check_sn_reached_max_retx(nack_sn);
|
||||
rlc_amd_retx_t& retx = retx_queue.push();
|
||||
retx.sn = nack_sn;
|
||||
retx.is_segment = false;
|
||||
|
@ -776,6 +785,30 @@ void rlc_am_nr_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes)
|
|||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to check if a SN has reached the max reTx threshold
|
||||
*
|
||||
* Caller _must_ hold the mutex when calling the function.
|
||||
* If the retx has been reached for a SN the upper layers (i.e. RRC/PDCP) will be informed.
|
||||
* The SN is _not_ removed from the Tx window, so retransmissions of that SN can still occur.
|
||||
*
|
||||
*
|
||||
* @param sn The SN of the PDU to check
|
||||
*/
|
||||
void rlc_am_nr_tx::check_sn_reached_max_retx(uint32_t sn)
|
||||
{
|
||||
if (tx_window[sn].retx_count == cfg.max_retx_thresh) {
|
||||
RlcWarning("Signaling max number of reTx=%d for SN=%d", tx_window[sn].retx_count, sn);
|
||||
parent->rrc->max_retx_attempted();
|
||||
srsran::pdcp_sn_vector_t pdcp_sns;
|
||||
pdcp_sns.push_back(tx_window[sn].pdcp_sn);
|
||||
parent->pdcp->notify_failure(parent->lcid, pdcp_sns);
|
||||
|
||||
std::lock_guard<std::mutex> lock(parent->metrics_mutex);
|
||||
parent->metrics.num_lost_pdus++;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t rlc_am_nr_tx::get_buffer_state()
|
||||
{
|
||||
uint32_t tx_queue = 0;
|
||||
|
|
|
@ -883,6 +883,74 @@ int retx_segment_test()
|
|||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// This test checks whether RLC informs upper layer when max retransmission has been reached
|
||||
int max_retx_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 = 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]));
|
||||
}
|
||||
|
||||
// Read 2 PDUs from RLC1 (1 byte each)
|
||||
const uint32_t n_pdus = 2;
|
||||
byte_buffer_t pdu_bufs[n_pdus];
|
||||
for (uint32_t i = 0; i < n_pdus; i++) {
|
||||
len = rlc1.read_pdu(pdu_bufs[i].msg, 3); // 2 byte header + 1 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()
|
||||
{
|
||||
|
@ -1016,6 +1084,7 @@ 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(discard_test() == SRSRAN_SUCCESS);
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue