mirror of https://github.com/PentHertz/srsLTE.git
lib,rlc_am_nr: starting to add test for segmenting retx. Changed sdu under segmentation to only hold the SN. The actual SDU already exists in the pdu stored in the tx_window.
This commit is contained in:
parent
581a99c616
commit
b1a33a07a1
|
@ -74,7 +74,7 @@ struct rlc_amd_tx_pdu_nr {
|
|||
const uint32_t rlc_sn = INVALID_RLC_SN;
|
||||
const uint32_t pdcp_sn = INVALID_RLC_SN;
|
||||
rlc_am_nr_pdu_header_t header = {};
|
||||
unique_byte_buffer_t buf = nullptr;
|
||||
unique_byte_buffer_t sdu_buf = nullptr;
|
||||
uint32_t retx_count = 0;
|
||||
struct pdu_segment {
|
||||
uint32_t so = 0;
|
||||
|
@ -104,10 +104,8 @@ public:
|
|||
void empty_queue() final;
|
||||
|
||||
// Data PDU helpers
|
||||
int build_new_sdu_segment(unique_byte_buffer_t tx_sdu,
|
||||
rlc_amd_tx_pdu_nr& tx_pdu,
|
||||
uint8_t* payload,
|
||||
uint32_t nof_bytes);
|
||||
int build_new_pdu(uint8_t* payload, uint32_t nof_bytes);
|
||||
int build_new_sdu_segment(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);
|
||||
|
||||
|
@ -149,7 +147,7 @@ private:
|
|||
|
||||
// Queues and buffers
|
||||
pdu_retx_queue<RLC_AM_WINDOW_SIZE> retx_queue;
|
||||
rlc_amd_tx_sdu_nr_t sdu_under_segmentation;
|
||||
uint32_t sdu_under_segmentation_sn = INVALID_RLC_SN; // SN of the SDU currently being segmented.
|
||||
|
||||
// Helper constants
|
||||
uint32_t min_hdr_size = 2;
|
||||
|
|
|
@ -67,6 +67,18 @@ bool rlc_am_nr_tx::has_data()
|
|||
tx_sdu_queue.get_n_sdus() != 1; // or if there is a SDU queued up for transmission
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the RLC PDU.
|
||||
*
|
||||
* Called by the MAC, trough the STACK thread.
|
||||
*
|
||||
* \param [payload] is a pointer to the buffer that will hold the PDU.
|
||||
* \param [nof_bytes] is the number of bytes the RLC is allowed to fill.
|
||||
*
|
||||
* \returns the number of bytes written to the payload buffer.
|
||||
* \remark: This will be called multiple times from the MAC,
|
||||
* while there is something to TX and enough space in the TB.
|
||||
*/
|
||||
uint32_t rlc_am_nr_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
|
@ -106,14 +118,14 @@ uint32_t rlc_am_nr_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes)
|
|||
}
|
||||
|
||||
// Send remaining segment, if it exists
|
||||
if (sdu_under_segmentation.rlc_sn != INVALID_RLC_SN) {
|
||||
if (not tx_window.has_sn(sdu_under_segmentation.rlc_sn)) {
|
||||
sdu_under_segmentation.rlc_sn = INVALID_RLC_SN;
|
||||
if (sdu_under_segmentation_sn != INVALID_RLC_SN) {
|
||||
if (not tx_window.has_sn(sdu_under_segmentation_sn)) {
|
||||
sdu_under_segmentation_sn = INVALID_RLC_SN;
|
||||
RlcError("SDU currently being segmented does not exist in tx_window. Aborting segmentation SN=%d",
|
||||
sdu_under_segmentation.rlc_sn);
|
||||
sdu_under_segmentation_sn);
|
||||
return 0;
|
||||
}
|
||||
return build_continuation_sdu_segment(tx_window[sdu_under_segmentation.rlc_sn], payload, nof_bytes);
|
||||
return build_continuation_sdu_segment(tx_window[sdu_under_segmentation_sn], payload, nof_bytes);
|
||||
}
|
||||
|
||||
// Check whether there is something to TX
|
||||
|
@ -122,6 +134,26 @@ uint32_t rlc_am_nr_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes)
|
|||
return 0;
|
||||
}
|
||||
|
||||
return build_new_pdu(payload, nof_bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a new RLC PDU, which contains the full SDU.
|
||||
*
|
||||
* Called by the MAC, trough the STACK thread.
|
||||
* This will be called after checking whether control, retransmission,
|
||||
* or segment PDUs needed to be transmitted first.
|
||||
*
|
||||
* This will read an SDU from the SDU queue, build a new PDU, and add it to the tx_window.
|
||||
* Segmentation will be done if necessary.
|
||||
*
|
||||
* \param [payload] is a pointer to the buffer that will hold the PDU.
|
||||
* \param [nof_bytes] is the number of bytes the RLC is allowed to fill.
|
||||
*
|
||||
* \returns the number of bytes written to the payload buffer.
|
||||
*/
|
||||
int rlc_am_nr_tx::build_new_pdu(uint8_t* payload, uint32_t nof_bytes)
|
||||
{
|
||||
// Read new SDU from TX queue
|
||||
unique_byte_buffer_t tx_sdu;
|
||||
RlcDebug("reading from RLC SDU queue. Queue size %d", tx_sdu_queue.size());
|
||||
|
@ -139,21 +171,22 @@ uint32_t rlc_am_nr_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes)
|
|||
// insert newly assigned SN into window and use reference for in-place operations
|
||||
// NOTE: from now on, we can't return from this function anymore before increasing tx_next
|
||||
rlc_amd_tx_pdu_nr& tx_pdu = tx_window.add_pdu(st.tx_next);
|
||||
tx_pdu.buf = srsran::make_byte_buffer();
|
||||
if (tx_pdu.buf == nullptr) {
|
||||
tx_pdu.sdu_buf = srsran::make_byte_buffer();
|
||||
if (tx_pdu.sdu_buf == nullptr) {
|
||||
RlcError("couldn't allocate PDU in %s().", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Copy SDU into PDU info
|
||||
memcpy(tx_pdu.sdu_buf->msg, tx_sdu->msg, tx_sdu->N_bytes);
|
||||
tx_pdu.sdu_buf->N_bytes = tx_sdu->N_bytes;
|
||||
|
||||
// Segment new SDU if necessary
|
||||
if (tx_sdu->N_bytes + min_hdr_size > nof_bytes) {
|
||||
RlcInfo("trying to build PDU segment from SDU.");
|
||||
return build_new_sdu_segment(std::move(tx_sdu), tx_pdu, payload, nof_bytes);
|
||||
return build_new_sdu_segment(tx_pdu, payload, nof_bytes);
|
||||
}
|
||||
|
||||
memcpy(tx_pdu.buf->msg, tx_sdu->msg, tx_sdu->N_bytes);
|
||||
tx_pdu.buf->N_bytes = tx_sdu->N_bytes;
|
||||
|
||||
// Prepare header
|
||||
rlc_am_nr_pdu_header_t hdr = {};
|
||||
hdr.dc = RLC_DC_FIELD_DATA_PDU;
|
||||
|
@ -179,18 +212,27 @@ uint32_t rlc_am_nr_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes)
|
|||
return tx_sdu->N_bytes;
|
||||
}
|
||||
|
||||
int rlc_am_nr_tx::build_new_sdu_segment(unique_byte_buffer_t tx_sdu,
|
||||
rlc_amd_tx_pdu_nr& tx_pdu,
|
||||
uint8_t* payload,
|
||||
uint32_t nof_bytes)
|
||||
/**
|
||||
* Builds a new RLC PDU segment.
|
||||
*
|
||||
* Called by the MAC, trough the STACK thread.
|
||||
*
|
||||
* \param [tx_pdu] is a pointer to the buffer that will hold the PDU.
|
||||
* \param [payload] is a pointer to the MAC buffer that will hold the PDU segment.
|
||||
* \param [nof_bytes] is the number of bytes the RLC is allowed to fill.
|
||||
*
|
||||
* \returns the number of bytes written to the payload buffer.
|
||||
* \remark: This functions assumes that the SDU has already been copied to tx_pdu.sdu_buf.
|
||||
*/
|
||||
int rlc_am_nr_tx::build_new_sdu_segment(rlc_amd_tx_pdu_nr& tx_pdu, uint8_t* payload, uint32_t nof_bytes)
|
||||
{
|
||||
RlcInfo("creating new SDU segment. Tx SDU (%d B), nof_bytes=%d B ", tx_sdu->N_bytes, nof_bytes);
|
||||
RlcInfo("creating new SDU segment. Tx SDU (%d B), nof_bytes=%d B ", tx_pdu.sdu_buf->N_bytes, nof_bytes);
|
||||
|
||||
// Sanity check: can this SDU be sent this in a single PDU?
|
||||
if ((tx_sdu->N_bytes + min_hdr_size) < nof_bytes) {
|
||||
if ((tx_pdu.sdu_buf->N_bytes + min_hdr_size) < nof_bytes) {
|
||||
RlcError("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,
|
||||
tx_pdu.sdu_buf->N_bytes,
|
||||
nof_bytes);
|
||||
return 0;
|
||||
}
|
||||
|
@ -223,11 +265,10 @@ int rlc_am_nr_tx::build_new_sdu_segment(unique_byte_buffer_t tx_sdu,
|
|||
// Copy PDU to payload
|
||||
uint32_t segment_payload_len = nof_bytes - hdr_len;
|
||||
srsran_assert((hdr_len + segment_payload_len) <= nof_bytes, "Error calculating hdr_len and segment_payload_len");
|
||||
memcpy(&payload[hdr_len], tx_pdu.buf->msg, segment_payload_len);
|
||||
memcpy(&payload[hdr_len], tx_pdu.sdu_buf->msg, segment_payload_len);
|
||||
|
||||
// Save SDU currently being segmented
|
||||
sdu_under_segmentation.rlc_sn = st.tx_next;
|
||||
sdu_under_segmentation.buf = std::move(tx_sdu);
|
||||
sdu_under_segmentation_sn = st.tx_next;
|
||||
|
||||
// Store Segment Info
|
||||
rlc_amd_tx_pdu_nr::pdu_segment segment_info;
|
||||
|
@ -239,19 +280,18 @@ int rlc_am_nr_tx::build_new_sdu_segment(unique_byte_buffer_t tx_sdu,
|
|||
int rlc_am_nr_tx::build_continuation_sdu_segment(rlc_amd_tx_pdu_nr& tx_pdu, uint8_t* payload, uint32_t nof_bytes)
|
||||
{
|
||||
RlcInfo("continuing SDU segment. SN=%d, Tx SDU (%d B), nof_bytes=%d B ",
|
||||
sdu_under_segmentation.rlc_sn,
|
||||
sdu_under_segmentation.buf->N_bytes,
|
||||
sdu_under_segmentation_sn,
|
||||
tx_pdu.sdu_buf->N_bytes,
|
||||
nof_bytes);
|
||||
|
||||
// Sanity check: is there an initial SDU segment?
|
||||
if (tx_pdu.segment_list.empty()) {
|
||||
RlcError("build_continuation_sdu_segment was called, but there was no initial segment. SN=%d, Tx SDU (%d B), "
|
||||
"nof_bytes=%d B ",
|
||||
sdu_under_segmentation.rlc_sn,
|
||||
sdu_under_segmentation.buf->N_bytes,
|
||||
sdu_under_segmentation_sn,
|
||||
tx_pdu.sdu_buf->N_bytes,
|
||||
nof_bytes);
|
||||
sdu_under_segmentation.rlc_sn = INVALID_RLC_SN;
|
||||
sdu_under_segmentation.buf = nullptr;
|
||||
sdu_under_segmentation_sn = INVALID_RLC_SN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -267,15 +307,16 @@ int rlc_am_nr_tx::build_continuation_sdu_segment(rlc_amd_tx_pdu_nr& tx_pdu, uint
|
|||
uint32_t last_byte = seg.so + seg.payload_len;
|
||||
RlcDebug("continuing SDU segment. SN=%d, last byte transmitted %d", tx_pdu.rlc_sn, last_byte);
|
||||
|
||||
// Sanity check: last byte must be smaller than SDU
|
||||
if (sdu_under_segmentation.buf->N_bytes < last_byte) {
|
||||
RlcError("last byte transmitted larger than SDU len. SDU len=%d B, last_byte=%d B", tx_pdu.buf->N_bytes, last_byte);
|
||||
// Sanity check: last byte must be smaller than SDU size
|
||||
if (last_byte > tx_pdu.sdu_buf->N_bytes) {
|
||||
RlcError(
|
||||
"last byte transmitted larger than SDU len. SDU len=%d B, last_byte=%d B", tx_pdu.sdu_buf->N_bytes, last_byte);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t segment_payload_full_len = sdu_under_segmentation.buf->N_bytes - last_byte + max_hdr_size; // SO is included
|
||||
uint32_t segment_payload_len = sdu_under_segmentation.buf->N_bytes - last_byte;
|
||||
rlc_nr_si_field_t si = {};
|
||||
uint32_t segment_payload_full_len = tx_pdu.sdu_buf->N_bytes - last_byte + max_hdr_size; // SO is included
|
||||
uint32_t segment_payload_len = tx_pdu.sdu_buf->N_bytes - last_byte;
|
||||
rlc_nr_si_field_t si = {};
|
||||
|
||||
if (segment_payload_full_len > nof_bytes) {
|
||||
RlcInfo("grant is not large enough for full SDU. "
|
||||
|
@ -313,7 +354,7 @@ int rlc_am_nr_tx::build_continuation_sdu_segment(rlc_amd_tx_pdu_nr& tx_pdu, uint
|
|||
|
||||
// Copy PDU to payload
|
||||
srsran_assert((hdr_len + segment_payload_len) <= nof_bytes, "Error calculating hdr_len and segment_payload_len");
|
||||
memcpy(&payload[hdr_len], &tx_pdu.buf->msg[last_byte], segment_payload_len);
|
||||
memcpy(&payload[hdr_len], &tx_pdu.sdu_buf->msg[last_byte], segment_payload_len);
|
||||
|
||||
// Store PDU segment info into tx_window
|
||||
rlc_amd_tx_pdu_nr::pdu_segment segment_info = {};
|
||||
|
@ -327,8 +368,7 @@ int rlc_am_nr_tx::build_continuation_sdu_segment(rlc_amd_tx_pdu_nr& tx_pdu, uint
|
|||
} else {
|
||||
RlcInfo("grant is large enough for full SDU."
|
||||
"Removing current SDU info");
|
||||
sdu_under_segmentation.rlc_sn = INVALID_RLC_SN;
|
||||
sdu_under_segmentation.buf = nullptr;
|
||||
sdu_under_segmentation_sn = INVALID_RLC_SN;
|
||||
}
|
||||
|
||||
return hdr_len + segment_payload_len;
|
||||
|
@ -361,22 +401,21 @@ int rlc_am_nr_tx::build_retx_pdu(unique_byte_buffer_t& tx_pdu, uint32_t nof_byte
|
|||
uint32_t hdr_len = rlc_am_nr_write_data_pdu_header(new_header, tx_pdu.get());
|
||||
|
||||
// Check if we exceed allocated number of bytes
|
||||
if (hdr_len + tx_window[retx.sn].buf->N_bytes > nof_bytes) {
|
||||
RlcWarning("segmentation not supported yet. Cannot provide retx PDU");
|
||||
if (hdr_len + tx_window[retx.sn].sdu_buf->N_bytes > nof_bytes) {
|
||||
RlcWarning("Trying to segment retx PDU");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
// TODO Consider re-segmentation
|
||||
|
||||
memcpy(&tx_pdu->msg[hdr_len], tx_window[retx.sn].buf->msg, tx_window[retx.sn].buf->N_bytes);
|
||||
tx_pdu->N_bytes += tx_window[retx.sn].buf->N_bytes;
|
||||
memcpy(&tx_pdu->msg[hdr_len], tx_window[retx.sn].sdu_buf->msg, tx_window[retx.sn].sdu_buf->N_bytes);
|
||||
tx_pdu->N_bytes += tx_window[retx.sn].sdu_buf->N_bytes;
|
||||
|
||||
retx_queue.pop();
|
||||
|
||||
RlcHexInfo(tx_window[retx.sn].buf->msg,
|
||||
tx_window[retx.sn].buf->N_bytes,
|
||||
RlcHexInfo(tx_window[retx.sn].sdu_buf->msg,
|
||||
tx_window[retx.sn].sdu_buf->N_bytes,
|
||||
"Original SDU SN=%d (%d B) (attempt %d/%d)",
|
||||
retx.sn,
|
||||
tx_window[retx.sn].buf->N_bytes,
|
||||
tx_window[retx.sn].sdu_buf->N_bytes,
|
||||
tx_window[retx.sn].retx_count + 1,
|
||||
cfg.max_retx_thresh);
|
||||
RlcHexInfo(tx_pdu->msg, tx_pdu->N_bytes, "retx PDU SN=%d (%d B)", retx.sn, tx_pdu->N_bytes);
|
||||
|
@ -463,7 +502,7 @@ void rlc_am_nr_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes)
|
|||
retx.sn = nack_sn;
|
||||
retx.is_segment = false;
|
||||
retx.so_start = 0;
|
||||
retx.so_end = pdu.buf->N_bytes;
|
||||
retx.so_end = pdu.sdu_buf->N_bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -410,7 +410,151 @@ int basic_segmentation_test()
|
|||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
int segment_retx_test()
|
||||
{
|
||||
rlc_am_tester tester;
|
||||
timer_handler timers(8);
|
||||
byte_buffer_t pdu_bufs[NBUFS];
|
||||
|
||||
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("segment retx PDU");
|
||||
|
||||
// before configuring entity
|
||||
TESTASSERT(0 == rlc1.get_buffer_state());
|
||||
|
||||
if (not rlc1.configure(rlc_config_t::default_rlc_am_nr_config())) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (not rlc2.configure(rlc_config_t::default_rlc_am_nr_config())) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Push 5 SDUs into RLC1
|
||||
unique_byte_buffer_t sdu_bufs[NBUFS];
|
||||
for (int i = 0; i < NBUFS; 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 = 3; // Give each buffer a size of 3 bytes
|
||||
sdu_bufs[i]->md.pdcp_sn = i; // PDCP SN for notifications
|
||||
rlc1.write_sdu(std::move(sdu_bufs[i]));
|
||||
}
|
||||
|
||||
TESTASSERT(25 == rlc1.get_buffer_state()); // 2 Bytes * NBUFFS (header size) + NBUFFS * 3 (data) = 25
|
||||
|
||||
// Read 5 PDUs from RLC1 (1 byte each)
|
||||
for (int i = 0; i < NBUFS; i++) {
|
||||
uint32_t len = rlc1.read_pdu(pdu_bufs[i].msg, 5); // 2 bytes for header + 3 byte payload
|
||||
pdu_bufs[i].N_bytes = len;
|
||||
TESTASSERT_EQ(5, len);
|
||||
}
|
||||
|
||||
TESTASSERT(0 == rlc1.get_buffer_state());
|
||||
|
||||
// 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.
|
||||
}
|
||||
}
|
||||
|
||||
// Only after t-reassembly has expired, will the status report include NACKs.
|
||||
TESTASSERT(3 == rlc2.get_buffer_state());
|
||||
{
|
||||
// Read status PDU from RLC2
|
||||
byte_buffer_t status_buf;
|
||||
int len = rlc2.read_pdu(status_buf.msg, 5);
|
||||
status_buf.N_bytes = len;
|
||||
|
||||
TESTASSERT(0 == rlc2.get_buffer_state());
|
||||
|
||||
// Assert status is correct
|
||||
rlc_am_nr_status_pdu_t status_check = {};
|
||||
rlc_am_nr_read_status_pdu(&status_buf, rlc_am_nr_sn_size_t::size12bits, &status_check);
|
||||
TESTASSERT(status_check.ack_sn == 3); // 3 is the next expected SN (i.e. the lost packet.)
|
||||
|
||||
// Write status PDU to RLC1
|
||||
rlc1.write_pdu(status_buf.msg, status_buf.N_bytes);
|
||||
}
|
||||
|
||||
// Step timers until reassambly timeout expires
|
||||
for (int cnt = 0; cnt < 35; cnt++) {
|
||||
timers.step_all();
|
||||
}
|
||||
|
||||
// t-reassembly has expired. There should be a NACK in the status report.
|
||||
TESTASSERT(5 == rlc2.get_buffer_state());
|
||||
{
|
||||
// Read status PDU from RLC2
|
||||
byte_buffer_t status_buf;
|
||||
int len = rlc2.read_pdu(status_buf.msg, 5);
|
||||
status_buf.N_bytes = len;
|
||||
|
||||
TESTASSERT(0 == rlc2.get_buffer_state());
|
||||
|
||||
// Assert status is correct
|
||||
rlc_am_nr_status_pdu_t status_check = {};
|
||||
rlc_am_nr_read_status_pdu(&status_buf, rlc_am_nr_sn_size_t::size12bits, &status_check);
|
||||
TESTASSERT(status_check.ack_sn == 5); // 5 is the next expected SN.
|
||||
TESTASSERT(status_check.N_nack == 1); // We lost one PDU.
|
||||
TESTASSERT(status_check.nacks[0].nack_sn == 3); // Lost PDU SN=3.
|
||||
|
||||
// Write status PDU to RLC1
|
||||
rlc1.write_pdu(status_buf.msg, status_buf.N_bytes);
|
||||
|
||||
// Check there is an Retx of SN=3
|
||||
TESTASSERT(5 == rlc1.get_buffer_state());
|
||||
}
|
||||
|
||||
{
|
||||
// Re-transmit PDU in 3 segments
|
||||
for (int i = 0; i < 3; i++) {
|
||||
byte_buffer_t retx_buf;
|
||||
int len = rlc1.read_pdu(retx_buf.msg, 3);
|
||||
retx_buf.N_bytes = len;
|
||||
TESTASSERT(3 == len);
|
||||
|
||||
rlc2.write_pdu(retx_buf.msg, retx_buf.N_bytes);
|
||||
}
|
||||
TESTASSERT(0 == rlc1.get_buffer_state());
|
||||
}
|
||||
|
||||
// Check statistics
|
||||
rlc_bearer_metrics_t metrics1 = rlc1.get_metrics();
|
||||
rlc_bearer_metrics_t metrics2 = rlc2.get_metrics();
|
||||
|
||||
// SDU metrics
|
||||
TESTASSERT_EQ(5, metrics1.num_tx_sdus);
|
||||
TESTASSERT_EQ(0, metrics1.num_rx_sdus);
|
||||
TESTASSERT_EQ(15, metrics1.num_tx_sdu_bytes);
|
||||
TESTASSERT_EQ(0, metrics1.num_rx_sdu_bytes);
|
||||
TESTASSERT_EQ(0, metrics1.num_lost_sdus);
|
||||
// PDU metrics
|
||||
TESTASSERT_EQ(5 + 3, metrics1.num_tx_pdus); // 3 re-transmissions
|
||||
TESTASSERT_EQ(2, metrics1.num_rx_pdus); // Two status PDU
|
||||
TESTASSERT_EQ(18,
|
||||
metrics1.num_tx_pdu_bytes); // 2 Bytes * NBUFFS (header size) + NBUFFS * 3 (data) + 3 rext (3 * 3) = 34
|
||||
TESTASSERT_EQ(3 + 5, metrics1.num_rx_pdu_bytes); // Two status PDU (one with a NACK)
|
||||
TESTASSERT_EQ(0, metrics1.num_lost_sdus); // No lost SDUs
|
||||
|
||||
// PDU metrics
|
||||
TESTASSERT_EQ(0, metrics2.num_tx_sdus);
|
||||
TESTASSERT_EQ(5, metrics2.num_rx_sdus);
|
||||
TESTASSERT_EQ(0, metrics2.num_tx_sdu_bytes);
|
||||
TESTASSERT_EQ(5, metrics2.num_rx_sdu_bytes);
|
||||
TESTASSERT_EQ(0, metrics2.num_lost_sdus);
|
||||
// SDU metrics
|
||||
TESTASSERT_EQ(2, metrics2.num_tx_pdus); // Two status PDUs
|
||||
TESTASSERT_EQ(5, metrics2.num_rx_pdus); // 5 PDUs (6 tx'ed, but one was lost)
|
||||
TESTASSERT_EQ(5 + 3, metrics2.num_tx_pdu_bytes); // Two status PDU (one with a NACK)
|
||||
TESTASSERT_EQ(15, metrics2.num_rx_pdu_bytes); // 2 Bytes * NBUFFS (header size) + NBUFFS (data) = 15
|
||||
TESTASSERT_EQ(0, metrics2.num_lost_sdus); // No lost SDUs
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// Setup the log message spy to intercept error and warning log entries from RLC
|
||||
if (!srslog::install_custom_sink(srsran::log_sink_message_spy::name(),
|
||||
|
@ -439,6 +583,7 @@ int main(int argc, char** argv)
|
|||
TESTASSERT(basic_test() == SRSRAN_SUCCESS);
|
||||
TESTASSERT(lost_pdu_test() == SRSRAN_SUCCESS);
|
||||
TESTASSERT(basic_segmentation_test() == SRSRAN_SUCCESS);
|
||||
TESTASSERT(segment_retx_test() == SRSRAN_SUCCESS);
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ public:
|
|||
int read_pdu_bcch_bch(const uint32_t tti, srsran::byte_buffer_t& buffer) final;
|
||||
int read_pdu_bcch_dlsch(uint32_t sib_index, srsran::byte_buffer_t& buffer) final;
|
||||
|
||||
/// User manegement
|
||||
/// User management
|
||||
int add_user(uint16_t rnti, uint32_t pcell_cc_idx) final;
|
||||
void rem_user(uint16_t rnti);
|
||||
int update_user(uint16_t new_rnti, uint16_t old_rnti) final;
|
||||
|
|
Loading…
Reference in New Issue