mirror of https://github.com/PentHertz/srsLTE.git
lib,rlc_am_nr: added initial logic to support receiving PDU segments.
This commit is contained in:
parent
aae1d9ad10
commit
8afea13d9a
|
@ -212,6 +212,7 @@ public:
|
||||||
void handle_data_pdu_full(uint8_t* payload, uint32_t nof_bytes, rlc_am_nr_pdu_header_t& header);
|
void handle_data_pdu_full(uint8_t* payload, uint32_t nof_bytes, rlc_am_nr_pdu_header_t& header);
|
||||||
bool inside_rx_window(uint32_t sn);
|
bool inside_rx_window(uint32_t sn);
|
||||||
void write_to_upper_layers(uint32_t lcid, unique_byte_buffer_t sdu);
|
void write_to_upper_layers(uint32_t lcid, unique_byte_buffer_t sdu);
|
||||||
|
bool have_all_segments_been_received(const std::list<rlc_amd_rx_pdu_nr>& segment_list);
|
||||||
|
|
||||||
// Metrics
|
// Metrics
|
||||||
uint32_t get_sdu_rx_latency_ms() final;
|
uint32_t get_sdu_rx_latency_ms() final;
|
||||||
|
|
|
@ -313,12 +313,20 @@ int rlc_am_nr_tx::build_continuation_sdu_segment(rlc_amd_tx_pdu_nr& tx_pdu, uint
|
||||||
// Copy PDU to payload
|
// Copy PDU to payload
|
||||||
memcpy(&payload[hdr_len], &tx_pdu.buf->msg[last_byte], segment_payload_len);
|
memcpy(&payload[hdr_len], &tx_pdu.buf->msg[last_byte], segment_payload_len);
|
||||||
|
|
||||||
|
// Store PDU segment info into tx_window
|
||||||
|
rlc_amd_tx_pdu_nr::pdu_segment segment_info = {};
|
||||||
|
segment_info.so = last_byte;
|
||||||
|
segment_info.payload_len = segment_payload_len;
|
||||||
|
tx_pdu.segment_list.push_back(segment_info);
|
||||||
|
|
||||||
if (si == rlc_nr_si_field_t::neither_first_nor_last_segment) {
|
if (si == rlc_nr_si_field_t::neither_first_nor_last_segment) {
|
||||||
logger->info("Grant is not large enough for full SDU."
|
logger->info("Grant is not large enough for full SDU."
|
||||||
"Storing SDU segment info");
|
"Storing SDU segment info");
|
||||||
} else {
|
} else {
|
||||||
logger->info("Grant is large enough for full SDU."
|
logger->info("Grant is large enough for full SDU."
|
||||||
"Removing current SDU info");
|
"Removing current SDU info");
|
||||||
|
current_sdu.rlc_sn = INVALID_RLC_SN;
|
||||||
|
current_sdu.buf = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return hdr_len + segment_payload_len;
|
return hdr_len + segment_payload_len;
|
||||||
|
@ -632,7 +640,7 @@ void rlc_am_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 5.2.3.2.2, discard duplicate PDUs
|
// Section 5.2.3.2.2, discard duplicate PDUs
|
||||||
if (rx_window.has_sn(header.sn)) {
|
if (rx_window.has_sn(header.sn) && rx_window[header.sn].fully_received) {
|
||||||
logger->info("%s Discarding duplicate SN=%d", parent->rb_name, header.sn);
|
logger->info("%s Discarding duplicate SN=%d", parent->rb_name, header.sn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -662,12 +670,65 @@ void rlc_am_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes)
|
||||||
rx_sdu.buf->N_bytes = nof_bytes - hdr_len;
|
rx_sdu.buf->N_bytes = nof_bytes - hdr_len;
|
||||||
rx_sdu.fully_received = true;
|
rx_sdu.fully_received = true;
|
||||||
write_to_upper_layers(parent->lcid, std::move(rx_window[header.sn].buf));
|
write_to_upper_layers(parent->lcid, std::move(rx_window[header.sn].buf));
|
||||||
} else {
|
} else if (header.si == rlc_nr_si_field_t::first_segment) { // Check whether it's a full SDU
|
||||||
// Check if all bytes of the RLC SDU with SN = x are received:
|
logger->info("Initial segment PDU. SN=%d.", header.sn);
|
||||||
// TODO
|
rlc_amd_rx_sdu_nr_t& rx_sdu = rx_window.add_pdu(header.sn);
|
||||||
if (header.si == rlc_nr_si_field_t::first_segment) { // Check whether it's a full SDU
|
|
||||||
} else if (header.si == rlc_nr_si_field_t::last_segment) {
|
rlc_amd_rx_pdu_nr pdu_segment = {};
|
||||||
|
pdu_segment.header = header;
|
||||||
|
pdu_segment.buf = srsran::make_byte_buffer();
|
||||||
|
if (pdu_segment.buf == nullptr) {
|
||||||
|
logger->error("Fatal Error: Couldn't allocate PDU in %s.", __FUNCTION__);
|
||||||
|
rx_window.remove_pdu(header.sn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memcpy(pdu_segment.buf->msg, payload + hdr_len, nof_bytes - hdr_len); // Don't copy header
|
||||||
|
pdu_segment.buf->N_bytes = nof_bytes - hdr_len;
|
||||||
|
rx_sdu.segments.push_back(std::move(pdu_segment));
|
||||||
} else if (header.si == rlc_nr_si_field_t::neither_first_nor_last_segment) {
|
} else if (header.si == rlc_nr_si_field_t::neither_first_nor_last_segment) {
|
||||||
|
logger->info("Middle segment PDU. SN=%d.", header.sn);
|
||||||
|
rlc_amd_rx_sdu_nr_t& rx_sdu = rx_window.has_sn(header.sn) ? rx_window[header.sn] : rx_window.add_pdu(header.sn);
|
||||||
|
|
||||||
|
rlc_amd_rx_pdu_nr pdu_segment = {};
|
||||||
|
pdu_segment.header = header;
|
||||||
|
pdu_segment.buf = srsran::make_byte_buffer();
|
||||||
|
if (pdu_segment.buf == nullptr) {
|
||||||
|
logger->error("Fatal Error: Couldn't allocate PDU in %s.", __FUNCTION__);
|
||||||
|
rx_window.remove_pdu(header.sn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memcpy(pdu_segment.buf->msg, payload + hdr_len, nof_bytes - hdr_len); // Don't copy header
|
||||||
|
pdu_segment.buf->N_bytes = nof_bytes - hdr_len;
|
||||||
|
rx_sdu.segments.push_back(std::move(pdu_segment));
|
||||||
|
} else if (header.si == rlc_nr_si_field_t::last_segment) {
|
||||||
|
logger->info("Final segment PDU. SN=%d.", header.sn);
|
||||||
|
rlc_amd_rx_sdu_nr_t& rx_sdu = rx_window.has_sn(header.sn) ? rx_window[header.sn] : rx_window.add_pdu(header.sn);
|
||||||
|
|
||||||
|
rlc_amd_rx_pdu_nr pdu_segment = {};
|
||||||
|
pdu_segment.header = header;
|
||||||
|
pdu_segment.buf = srsran::make_byte_buffer();
|
||||||
|
if (pdu_segment.buf == nullptr) {
|
||||||
|
logger->error("Fatal Error: Couldn't allocate PDU in %s.", __FUNCTION__);
|
||||||
|
rx_window.remove_pdu(header.sn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memcpy(pdu_segment.buf->msg, payload + hdr_len, nof_bytes - hdr_len); // Don't copy header
|
||||||
|
pdu_segment.buf->N_bytes = nof_bytes - hdr_len;
|
||||||
|
rx_sdu.segments.push_back(std::move(pdu_segment));
|
||||||
|
rx_sdu.fully_received = have_all_segments_been_received(rx_sdu.segments);
|
||||||
|
if (rx_sdu.fully_received) {
|
||||||
|
logger->info("Fully received segmented SDU. SN=%d.", header.sn);
|
||||||
|
rx_sdu.buf = srsran::make_byte_buffer();
|
||||||
|
if (rx_sdu.buf == nullptr) {
|
||||||
|
logger->error("Fatal Error: Couldn't allocate PDU in %s.", __FUNCTION__);
|
||||||
|
rx_window.remove_pdu(header.sn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const auto& it : rx_sdu.segments) {
|
||||||
|
memcpy(&rx_sdu.buf->msg[rx_sdu.buf->N_bytes], it.buf->msg, it.buf->N_bytes);
|
||||||
|
rx_sdu.buf->N_bytes += it.buf->N_bytes;
|
||||||
|
}
|
||||||
|
write_to_upper_layers(parent->lcid, std::move(rx_window[header.sn].buf));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -756,8 +817,8 @@ void rlc_am_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes)
|
||||||
if (st.rx_next_highest > st.rx_next + 1) {
|
if (st.rx_next_highest > st.rx_next + 1) {
|
||||||
restart_reassembly_timer = true;
|
restart_reassembly_timer = true;
|
||||||
}
|
}
|
||||||
if (st.rx_next_highest == st.rx_next + 1 &&
|
if (st.rx_next_highest == st.rx_next + 1 && rx_window.has_sn(st.rx_next + 1) &&
|
||||||
rx_window[st.rx_next + 1].fully_received == false) { // TODO: does the last by need to be received?
|
not rx_window[st.rx_next + 1].fully_received) {
|
||||||
restart_reassembly_timer = true;
|
restart_reassembly_timer = true;
|
||||||
}
|
}
|
||||||
if (restart_reassembly_timer) {
|
if (restart_reassembly_timer) {
|
||||||
|
@ -905,6 +966,27 @@ uint32_t rlc_am_nr_rx::get_rx_buffered_bytes()
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool rlc_am_nr_rx::have_all_segments_been_received(const std::list<rlc_amd_rx_pdu_nr>& segment_list)
|
||||||
|
{
|
||||||
|
if (segment_list.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we have received the last segment
|
||||||
|
if ((--segment_list.end())->header.si != rlc_nr_si_field_t::last_segment) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if all segments have been received
|
||||||
|
uint32_t next_byte = 0;
|
||||||
|
for (const auto& it : segment_list) {
|
||||||
|
if (it.header.so != next_byte) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
next_byte += it.buf->N_bytes;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Debug Helpers
|
* Debug Helpers
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -371,7 +371,8 @@ int basic_segmentation_test()
|
||||||
rlc1.write_sdu(std::move(sdu));
|
rlc1.write_sdu(std::move(sdu));
|
||||||
|
|
||||||
// Read 3 PDUs
|
// Read 3 PDUs
|
||||||
unique_byte_buffer_t pdu_bufs[3];
|
constexpr uint16_t n_pdus = 3;
|
||||||
|
unique_byte_buffer_t pdu_bufs[n_pdus];
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
pdu_bufs[i] = srsran::make_byte_buffer();
|
pdu_bufs[i] = srsran::make_byte_buffer();
|
||||||
TESTASSERT(nullptr != pdu_bufs[i]);
|
TESTASSERT(nullptr != pdu_bufs[i]);
|
||||||
|
@ -384,6 +385,28 @@ int basic_segmentation_test()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write 5 PDUs into RLC2
|
||||||
|
for (int i = 0; i < n_pdus; i++) {
|
||||||
|
rlc2.write_pdu(pdu_bufs[i]->msg, pdu_bufs[i]->N_bytes); // Don't write RLC_SN=3.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check statistics
|
||||||
|
rlc_bearer_metrics_t metrics1 = rlc1.get_metrics();
|
||||||
|
rlc_bearer_metrics_t metrics2 = rlc2.get_metrics();
|
||||||
|
|
||||||
|
// SDU metrics
|
||||||
|
TESTASSERT_EQ(0, metrics2.num_tx_sdus);
|
||||||
|
TESTASSERT_EQ(1, metrics2.num_rx_sdus);
|
||||||
|
TESTASSERT_EQ(0, metrics2.num_tx_sdu_bytes);
|
||||||
|
TESTASSERT_EQ(3, metrics2.num_rx_sdu_bytes);
|
||||||
|
TESTASSERT_EQ(0, metrics2.num_lost_sdus);
|
||||||
|
// PDU metrics
|
||||||
|
TESTASSERT_EQ(0, metrics2.num_tx_pdus);
|
||||||
|
TESTASSERT_EQ(3, metrics2.num_rx_pdus); // 5 PDUs (6 tx'ed, but one was lost)
|
||||||
|
TESTASSERT_EQ(0, metrics2.num_tx_pdu_bytes); // Two status PDU (one with a NACK)
|
||||||
|
TESTASSERT_EQ(13, metrics2.num_rx_pdu_bytes); // 1 PDU (No SO) + 2 PDUs (with SO) = 3 + 2*5
|
||||||
|
TESTASSERT_EQ(0, metrics2.num_lost_sdus); // No lost SDUs
|
||||||
|
|
||||||
return SRSRAN_SUCCESS;
|
return SRSRAN_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue