Added the ability of the RLC AM to notify the PDCP of the acknowledged

PDCP PDUs. This includes:

- Modifying the byte_buffer_t to include PDCP SN meta-data. This way,
  the RLC can keep track of the ack'ed bytes for a specific PDCP PDU.
- Added in the RLC an `undelivered_sdu_info queue`, to keep track of the
  amount of ack'ed bytes and the total size of the PDCP PDU,
  so the RLC can know when delivery is finished.
- Added an interface between the PDCP and the RLC so that the RLC can
  notify the PDCP when it receives an ack from the status PDUs. The RLC
  passes to the PDCP a vector of all the ack'ed pdus in a rx'ed status PDU.
- Added some tests to the notify functionality. This includes some tests
  where the PDUs are acked imediatly, and one test where the PDU is
  retx'ed.
master
Pedro Alvarez 4 years ago
parent 3dab82c42f
commit de90b4753f

@ -101,6 +101,10 @@ public:
char debug_name[SRSLTE_BUFFER_POOL_LOG_NAME_LEN]; char debug_name[SRSLTE_BUFFER_POOL_LOG_NAME_LEN];
#endif #endif
struct buffer_metadata_t {
uint32_t pdcp_sn;
} md;
byte_buffer_t() : N_bytes(0) byte_buffer_t() : N_bytes(0)
{ {
bzero(buffer, SRSLTE_MAX_BUFFER_SIZE_BYTES); bzero(buffer, SRSLTE_MAX_BUFFER_SIZE_BYTES);
@ -116,6 +120,7 @@ public:
msg = &buffer[SRSLTE_BUFFER_HEADER_OFFSET]; msg = &buffer[SRSLTE_BUFFER_HEADER_OFFSET];
next = NULL; next = NULL;
// copy actual contents // copy actual contents
md = buf.md;
N_bytes = buf.N_bytes; N_bytes = buf.N_bytes;
memcpy(msg, buf.msg, N_bytes); memcpy(msg, buf.msg, N_bytes);
} }
@ -128,6 +133,7 @@ public:
msg = &buffer[SRSLTE_BUFFER_HEADER_OFFSET]; msg = &buffer[SRSLTE_BUFFER_HEADER_OFFSET];
next = NULL; next = NULL;
N_bytes = buf.N_bytes; N_bytes = buf.N_bytes;
md = buf.md;
memcpy(msg, buf.msg, N_bytes); memcpy(msg, buf.msg, N_bytes);
return *this; return *this;
} }
@ -135,6 +141,7 @@ public:
{ {
msg = &buffer[SRSLTE_BUFFER_HEADER_OFFSET]; msg = &buffer[SRSLTE_BUFFER_HEADER_OFFSET];
N_bytes = 0; N_bytes = 0;
md = {};
#ifdef ENABLE_TIMESTAMP #ifdef ENABLE_TIMESTAMP
timestamp_is_set = false; timestamp_is_set = false;
#endif #endif

@ -387,7 +387,8 @@ class pdcp_interface_rlc
{ {
public: public:
/* RLC calls PDCP to push a PDCP PDU. */ /* RLC calls PDCP to push a PDCP PDU. */
virtual void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; virtual void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0;
virtual void notify_delivery(uint16_t rnti, uint32_t lcid, const std::vector<uint32_t>& pdcp_sns) = 0;
}; };
// RRC interface for RLC // RRC interface for RLC

@ -82,8 +82,10 @@ class pdcp_interface_rlc_nr
{ {
public: public:
/* RLC calls PDCP to push a PDCP PDU. */ /* RLC calls PDCP to push a PDCP PDU. */
virtual void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; virtual void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0;
virtual void notify_delivery(uint16_t rnti, uint32_t lcid, const std::vector<uint32_t>& tx_count) = 0;
}; };
class pdcp_interface_rrc_nr class pdcp_interface_rrc_nr
{ {
public: public:
@ -96,6 +98,7 @@ public:
virtual void enable_integrity(uint16_t rnti, uint32_t lcid) = 0; virtual void enable_integrity(uint16_t rnti, uint32_t lcid) = 0;
virtual void enable_encryption(uint16_t rnti, uint32_t lcid) = 0; virtual void enable_encryption(uint16_t rnti, uint32_t lcid) = 0;
}; };
class pdcp_interface_sdap_nr class pdcp_interface_sdap_nr
{ {
public: public:

@ -247,8 +247,8 @@ public:
virtual uint32_t get_ipv4_addr() = 0; virtual uint32_t get_ipv4_addr() = 0;
virtual bool get_ipv6_addr(uint8_t* ipv6_addr) = 0; virtual bool get_ipv6_addr(uint8_t* ipv6_addr) = 0;
virtual void virtual void
plmn_search_completed(const rrc_interface_nas::found_plmn_t found_plmns[rrc_interface_nas::MAX_FOUND_PLMNS], plmn_search_completed(const rrc_interface_nas::found_plmn_t found_plmns[rrc_interface_nas::MAX_FOUND_PLMNS],
int nof_plmns) = 0; int nof_plmns) = 0;
virtual bool connection_request_completed(bool outcome) = 0; virtual bool connection_request_completed(bool outcome) = 0;
}; };
@ -298,11 +298,12 @@ class pdcp_interface_rlc
{ {
public: public:
/* RLC calls PDCP to push a PDCP PDU. */ /* RLC calls PDCP to push a PDCP PDU. */
virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0;
virtual void write_pdu_bcch_bch(srslte::unique_byte_buffer_t sdu) = 0; virtual void write_pdu_bcch_bch(srslte::unique_byte_buffer_t sdu) = 0;
virtual void write_pdu_bcch_dlsch(srslte::unique_byte_buffer_t sdu) = 0; virtual void write_pdu_bcch_dlsch(srslte::unique_byte_buffer_t sdu) = 0;
virtual void write_pdu_pcch(srslte::unique_byte_buffer_t sdu) = 0; virtual void write_pdu_pcch(srslte::unique_byte_buffer_t sdu) = 0;
virtual void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; virtual void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0;
virtual void notify_delivery(uint32_t lcid, const std::vector<uint32_t>& pdcp_sn) = 0;
}; };
class pdcp_interface_gw class pdcp_interface_gw
@ -630,8 +631,8 @@ public:
} prach_info_t; } prach_info_t;
virtual void virtual void
prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm, float ta_base_sec = 0.0f) = 0; prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm, float ta_base_sec = 0.0f) = 0;
virtual prach_info_t prach_get_info() = 0; virtual prach_info_t prach_get_info() = 0;
/* Indicates the transmission of a SR signal in the next opportunity */ /* Indicates the transmission of a SR signal in the next opportunity */
virtual void sr_send() = 0; virtual void sr_send() = 0;

@ -56,6 +56,7 @@ public:
void write_pdu_bcch_bch(unique_byte_buffer_t sdu) override; void write_pdu_bcch_bch(unique_byte_buffer_t sdu) override;
void write_pdu_bcch_dlsch(unique_byte_buffer_t sdu) override; void write_pdu_bcch_dlsch(unique_byte_buffer_t sdu) override;
void write_pdu_pcch(unique_byte_buffer_t sdu) override; void write_pdu_pcch(unique_byte_buffer_t sdu) override;
void notify_delivery(uint32_t lcid, const std::vector<uint32_t>& pdcp_sn) override;
// eNB-only methods // eNB-only methods
std::map<uint32_t, srslte::unique_byte_buffer_t> get_buffered_pdus(uint32_t lcid); std::map<uint32_t, srslte::unique_byte_buffer_t> get_buffered_pdus(uint32_t lcid);

@ -110,7 +110,8 @@ public:
virtual void write_sdu(unique_byte_buffer_t sdu) = 0; virtual void write_sdu(unique_byte_buffer_t sdu) = 0;
// RLC interface // RLC interface
virtual void write_pdu(unique_byte_buffer_t pdu) = 0; virtual void write_pdu(unique_byte_buffer_t pdu) = 0;
virtual void notify_delivery(const std::vector<uint32_t>& tx_count) = 0;
virtual void get_bearer_state(pdcp_lte_state_t* state) = 0; virtual void get_bearer_state(pdcp_lte_state_t* state) = 0;
virtual void set_bearer_state(const pdcp_lte_state_t& state) = 0; virtual void set_bearer_state(const pdcp_lte_state_t& state) = 0;

@ -53,6 +53,7 @@ public:
// RLC interface // RLC interface
void write_pdu(unique_byte_buffer_t pdu) override; void write_pdu(unique_byte_buffer_t pdu) override;
void notify_delivery(const std::vector<uint32_t>& pdcp_sns) override;
// Config helpers // Config helpers
bool check_valid_config(); bool check_valid_config();

@ -49,6 +49,7 @@ public:
// RLC interface // RLC interface
void write_pdu(unique_byte_buffer_t pdu) final; void write_pdu(unique_byte_buffer_t pdu) final;
void notify_delivery(const std::vector<uint32_t>& tx_count) final;
// State variable setters (should be used only for testing) // State variable setters (should be used only for testing)
void set_tx_next(uint32_t tx_next_) { tx_next = tx_next_; } void set_tx_next(uint32_t tx_next_) { tx_next = tx_next_; }

@ -40,10 +40,11 @@ struct rlc_amd_rx_pdu_segments_t {
}; };
struct rlc_amd_tx_pdu_t { struct rlc_amd_tx_pdu_t {
rlc_amd_pdu_header_t header; rlc_amd_pdu_header_t header;
unique_byte_buffer_t buf; unique_byte_buffer_t buf;
uint32_t retx_count; uint32_t retx_count;
bool is_acked; bool is_acked;
std::array<uint32_t, RLC_AM_WINDOW_SIZE> pdcp_tx_counts;
}; };
struct rlc_amd_retx_t { struct rlc_amd_retx_t {
@ -53,6 +54,12 @@ struct rlc_amd_retx_t {
uint32_t so_end; uint32_t so_end;
}; };
struct pdcp_sdu_info_t {
uint32_t sn;
uint32_t acked_bytes;
uint32_t total_bytes;
};
class rlc_am_lte : public rlc_common class rlc_am_lte : public rlc_common
{ {
public: public:
@ -145,7 +152,7 @@ private:
// TX SDU buffers // TX SDU buffers
byte_buffer_queue tx_sdu_queue; byte_buffer_queue tx_sdu_queue;
unique_byte_buffer_t tx_sdu; unique_byte_buffer_t tx_sdu = nullptr;
bool tx_enabled = false; bool tx_enabled = false;
@ -174,6 +181,10 @@ private:
srslte::timer_handler::unique_timer poll_retx_timer; srslte::timer_handler::unique_timer poll_retx_timer;
srslte::timer_handler::unique_timer status_prohibit_timer; srslte::timer_handler::unique_timer status_prohibit_timer;
// SDU info for PDCP notifications
uint32_t pdcp_info_queue_capacity = 128;
std::map<uint32_t, pdcp_sdu_info_t> undelivered_sdu_info_queue;
// Callback function for buffer status report // Callback function for buffer status report
bsr_callback_t bsr_callback; bsr_callback_t bsr_callback;

@ -256,9 +256,9 @@ public:
virtual void reset_metrics() = 0; virtual void reset_metrics() = 0;
// PDCP interface // PDCP interface
virtual void write_sdu(unique_byte_buffer_t sdu) = 0; virtual void write_sdu(unique_byte_buffer_t sdu) = 0;
virtual void discard_sdu(uint32_t discard_sn) = 0; virtual void discard_sdu(uint32_t discard_sn) = 0;
virtual bool sdu_queue_is_full() = 0; virtual bool sdu_queue_is_full() = 0;
// MAC interface // MAC interface
virtual bool has_data() = 0; virtual bool has_data() = 0;

@ -282,6 +282,15 @@ void pdcp::write_pdu_mch(uint32_t lcid, unique_byte_buffer_t sdu)
} }
} }
void pdcp::notify_delivery(uint32_t lcid, const std::vector<uint32_t>& pdcp_sns)
{
if (valid_lcid(lcid)) {
pdcp_array.at(lcid)->notify_delivery(pdcp_sns);
} else {
pdcp_log->warning("Could not notify delivery: lcid=%d, nof_sn=%ld.\n", lcid, pdcp_sns.size());
}
}
bool pdcp::valid_lcid(uint32_t lcid) bool pdcp::valid_lcid(uint32_t lcid)
{ {
if (lcid >= SRSLTE_N_RADIO_BEARERS) { if (lcid >= SRSLTE_N_RADIO_BEARERS) {

@ -136,6 +136,9 @@ void pdcp_entity_lte::write_sdu(unique_byte_buffer_t sdu)
srslte_direction_text[integrity_direction], srslte_direction_text[integrity_direction],
srslte_direction_text[encryption_direction]); srslte_direction_text[encryption_direction]);
// Set SDU metadata for RLC AM
sdu->md.pdcp_sn = st.next_pdcp_tx_sn;
// Increment NEXT_PDCP_TX_SN and TX_HFN // Increment NEXT_PDCP_TX_SN and TX_HFN
st.next_pdcp_tx_sn++; st.next_pdcp_tx_sn++;
if (st.next_pdcp_tx_sn > maximum_pdcp_sn) { if (st.next_pdcp_tx_sn > maximum_pdcp_sn) {
@ -302,7 +305,9 @@ void pdcp_entity_lte::handle_am_drb_pdu(srslte::unique_byte_buffer_t pdu)
last_submit_diff_sn, last_submit_diff_sn,
reordering_window); reordering_window);
return; // Discard return; // Discard
} else if ((int32_t)(st.next_pdcp_rx_sn - sn) > (int32_t)reordering_window) { }
if ((int32_t)(st.next_pdcp_rx_sn - sn) > (int32_t)reordering_window) {
log->debug("(Next_PDCP_RX_SN - SN) is larger than re-ordering window.\n"); log->debug("(Next_PDCP_RX_SN - SN) is larger than re-ordering window.\n");
st.rx_hfn++; st.rx_hfn++;
count = (st.rx_hfn << cfg.sn_len) | sn; count = (st.rx_hfn << cfg.sn_len) | sn;
@ -334,6 +339,14 @@ void pdcp_entity_lte::handle_am_drb_pdu(srslte::unique_byte_buffer_t pdu)
gw->write_pdu(lcid, std::move(pdu)); gw->write_pdu(lcid, std::move(pdu));
} }
/****************************************************************************
* Delivery notifications from RLC
***************************************************************************/
void pdcp_entity_lte::notify_delivery(const std::vector<uint32_t>& pdcp_sns)
{
log->debug("Received delivery notification from RLC. Number of PDU notified=%ld\n", pdcp_sns.size());
}
/**************************************************************************** /****************************************************************************
* Config checking helper * Config checking helper
***************************************************************************/ ***************************************************************************/

@ -106,12 +106,15 @@ void pdcp_entity_nr::write_sdu(unique_byte_buffer_t sdu)
// Append MAC-I // Append MAC-I
append_mac(sdu, mac); append_mac(sdu, mac);
// Increment TX_NEXT // Set meta-data for RLC AM
tx_next++; sdu->md.pdcp_sn = tx_next;
// Check if PDCP is associated with more than on RLC entity TODO // Check if PDCP is associated with more than on RLC entity TODO
// Write to lower layers // Write to lower layers
rlc->write_sdu(lcid, std::move(sdu)); rlc->write_sdu(lcid, std::move(sdu));
// Increment TX_NEXT
tx_next++;
} }
// RLC interface // RLC interface
@ -199,6 +202,12 @@ void pdcp_entity_nr::write_pdu(unique_byte_buffer_t pdu)
} }
} }
// Notification of delivery
void pdcp_entity_nr::notify_delivery(const std::vector<uint32_t>& pdcp_sns)
{
log->debug("Received delivery notification from RLC. Nof SNs=%ld\n", pdcp_sns.size());
}
/* /*
* Packing / Unpacking Helpers * Packing / Unpacking Helpers
*/ */

@ -356,6 +356,12 @@ int rlc_am_lte::rlc_am_lte_tx::write_sdu(unique_byte_buffer_t sdu)
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
// Get SDU info
pdcp_sdu_info_t info = {};
info.sn = sdu->md.pdcp_sn;
info.total_bytes = sdu->N_bytes;
// Store SDU
uint8_t* msg_ptr = sdu->msg; uint8_t* msg_ptr = sdu->msg;
uint32_t nof_bytes = sdu->N_bytes; uint32_t nof_bytes = sdu->N_bytes;
srslte::error_type<unique_byte_buffer_t> ret = tx_sdu_queue.try_write(std::move(sdu)); srslte::error_type<unique_byte_buffer_t> ret = tx_sdu_queue.try_write(std::move(sdu));
@ -373,6 +379,16 @@ int rlc_am_lte::rlc_am_lte_tx::write_sdu(unique_byte_buffer_t sdu)
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
// Store SDU info
uint32_t info_count = undelivered_sdu_info_queue.count(info.sn);
if (info_count != 0) {
log->error("PDCP SDU info alreay exists\n");
return SRSLTE_ERROR;
} else if (info_count > pdcp_info_queue_capacity) {
log->error("PDCP SDU info exceeds maximum queue capacity\n");
return SRSLTE_ERROR;
}
undelivered_sdu_info_queue[info.sn] = info;
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
@ -829,6 +845,9 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt
log->debug("%s Building PDU - pdu_space: %d, head_len: %d \n", RB_NAME, pdu_space, head_len); log->debug("%s Building PDU - pdu_space: %d, head_len: %d \n", RB_NAME, pdu_space, head_len);
// Helper to keep track of the PDCP counts for each RLC PDU
std::array<uint32_t, RLC_AM_WINDOW_SIZE> pdcp_tx_counts = {};
// Check for SDU segment // Check for SDU segment
if (tx_sdu != NULL) { if (tx_sdu != NULL) {
to_move = ((pdu_space - head_len) >= tx_sdu->N_bytes) ? tx_sdu->N_bytes : pdu_space - head_len; to_move = ((pdu_space - head_len) >= tx_sdu->N_bytes) ? tx_sdu->N_bytes : pdu_space - head_len;
@ -838,6 +857,7 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt
pdu->N_bytes += to_move; pdu->N_bytes += to_move;
tx_sdu->N_bytes -= to_move; tx_sdu->N_bytes -= to_move;
tx_sdu->msg += to_move; tx_sdu->msg += to_move;
pdcp_tx_counts[0] = tx_sdu->md.pdcp_sn;
if (tx_sdu->N_bytes == 0) { if (tx_sdu->N_bytes == 0) {
log->debug("%s Complete SDU scheduled for tx.\n", RB_NAME); log->debug("%s Complete SDU scheduled for tx.\n", RB_NAME);
tx_sdu.reset(); tx_sdu.reset();
@ -877,6 +897,7 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt
pdu->N_bytes += to_move; pdu->N_bytes += to_move;
tx_sdu->N_bytes -= to_move; tx_sdu->N_bytes -= to_move;
tx_sdu->msg += to_move; tx_sdu->msg += to_move;
pdcp_tx_counts[header.N_li] = tx_sdu->md.pdcp_sn;
if (tx_sdu->N_bytes == 0) { if (tx_sdu->N_bytes == 0) {
log->debug("%s Complete SDU scheduled for tx.\n", RB_NAME); log->debug("%s Complete SDU scheduled for tx.\n", RB_NAME);
tx_sdu.reset(); tx_sdu.reset();
@ -925,11 +946,12 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt
vt_s = (vt_s + 1) % MOD; vt_s = (vt_s + 1) % MOD;
// Place PDU in tx_window, write header and TX // Place PDU in tx_window, write header and TX
tx_window[header.sn].buf = std::move(pdu); tx_window[header.sn].buf = std::move(pdu);
tx_window[header.sn].header = header; tx_window[header.sn].header = header;
tx_window[header.sn].is_acked = false; tx_window[header.sn].is_acked = false;
tx_window[header.sn].retx_count = 0; tx_window[header.sn].retx_count = 0;
const byte_buffer_t* buffer_ptr = tx_window[header.sn].buf.get(); tx_window[header.sn].pdcp_tx_counts = pdcp_tx_counts;
const byte_buffer_t* buffer_ptr = tx_window[header.sn].buf.get();
uint8_t* ptr = payload; uint8_t* ptr = payload;
rlc_am_write_data_pdu_header(&header, &ptr); rlc_am_write_data_pdu_header(&header, &ptr);
@ -967,8 +989,9 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no
// Handle ACKs and NACKs // Handle ACKs and NACKs
std::map<uint32_t, rlc_amd_tx_pdu_t>::iterator it; std::map<uint32_t, rlc_amd_tx_pdu_t>::iterator it;
bool update_vt_a = true; bool update_vt_a = true;
uint32_t i = vt_a; uint32_t i = vt_a;
std::vector<uint32_t> notify_info_vec = {};
while (TX_MOD_BASE(i) < TX_MOD_BASE(status.ack_sn) && TX_MOD_BASE(i) < TX_MOD_BASE(vt_s)) { while (TX_MOD_BASE(i) < TX_MOD_BASE(status.ack_sn) && TX_MOD_BASE(i) < TX_MOD_BASE(vt_s)) {
bool nack = false; bool nack = false;
@ -1027,6 +1050,28 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no
it = tx_window.find(i); it = tx_window.find(i);
if (it != tx_window.end()) { if (it != tx_window.end()) {
if (update_vt_a) { if (update_vt_a) {
// Notify PDCP of the number of bytes succesfully delivered
uint32_t notified_bytes = 0;
uint32_t nof_bytes = 0;
uint32_t pdcp_sn = 0;
for (uint32_t pdcp_notify_it = 0; pdcp_notify_it < it->second.header.N_li; pdcp_notify_it++) {
nof_bytes = it->second.header.li[pdcp_notify_it];
pdcp_sn = it->second.pdcp_tx_counts[pdcp_notify_it];
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);
notify_info_vec.push_back(pdcp_sn);
log->debug("Reporting to PDCP: TX COUNT=%d, nof_bytes=%d\n", pdcp_sn, nof_bytes);
}
}
pdcp_sn = it->second.pdcp_tx_counts[it->second.header.N_li];
nof_bytes = it->second.buf->N_bytes - notified_bytes; // Notify last SDU
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);
notify_info_vec.push_back(pdcp_sn);
log->debug("Reporting to PDCP: TX COUNT=%d, nof_bytes=%d\n", pdcp_sn, nof_bytes);
}
tx_window.erase(it); tx_window.erase(it);
vt_a = (vt_a + 1) % MOD; vt_a = (vt_a + 1) % MOD;
vt_ms = (vt_ms + 1) % MOD; vt_ms = (vt_ms + 1) % MOD;
@ -1037,6 +1082,10 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no
i = (i + 1) % MOD; i = (i + 1) % MOD;
} }
if (not notify_info_vec.empty()) {
parent->pdcp->notify_delivery(parent->lcid, notify_info_vec);
}
debug_state(); debug_state();
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);

@ -18,6 +18,10 @@ add_executable(rlc_am_test rlc_am_test.cc)
target_link_libraries(rlc_am_test srslte_upper srslte_phy srslte_common) target_link_libraries(rlc_am_test srslte_upper srslte_phy srslte_common)
add_test(rlc_am_test rlc_am_test) add_test(rlc_am_test rlc_am_test)
add_executable(rlc_am_notify_pdcp_test rlc_am_notify_pdcp_test.cc)
target_link_libraries(rlc_am_notify_pdcp_test srslte_upper srslte_phy)
add_test(rlc_am_notify_pdcp_test rlc_am_notify_pdcp_test)
if (ENABLE_5GNR) if (ENABLE_5GNR)
add_executable(rlc_am_nr_pdu_test rlc_am_nr_pdu_test.cc) add_executable(rlc_am_nr_pdu_test rlc_am_nr_pdu_test.cc)
target_link_libraries(rlc_am_nr_pdu_test srslte_upper srslte_phy) target_link_libraries(rlc_am_nr_pdu_test srslte_upper srslte_phy)

@ -0,0 +1,516 @@
/*
* Copyright 2013-2020 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include "srslte/common/test_common.h"
#include "srslte/upper/rlc_am_lte.h"
#include <iostream>
srslte::log_ref rlc_log("RLC");
class pdcp_tester : public srsue::pdcp_interface_rlc
{
public:
std::map<uint32_t, uint32_t> notified_counts; // Map of PDCP Tx count to acknoledged bytes
// PDCP interface
void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu) {}
void write_pdu_bcch_bch(srslte::unique_byte_buffer_t sdu) {}
void write_pdu_bcch_dlsch(srslte::unique_byte_buffer_t sdu) {}
void write_pdu_pcch(srslte::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<uint32_t>& 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;
// std::cout << "Notified " << notified_counts[tx_count] << "Tx count" << tx_count << "nof_bytes" << nof_bytes
// << std::endl;
}
}
};
class rrc_tester : public srsue::rrc_interface_rlc
{
void max_retx_attempted() {}
std::string get_rb_name(uint32_t lcid) { return "DRB1"; }
void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) {}
};
// Simple test of a single TX PDU and an imediate ACK
int simple_sdu_notify_test()
{
srslte::byte_buffer_pool* pool = srslte::byte_buffer_pool::get_instance();
pdcp_tester pdcp;
rrc_tester rrc;
srslte::timer_handler timers(8);
srslte::rlc_am_lte rlc(rlc_log, 1, &pdcp, &rrc, &timers);
uint8_t sdu[] = {0x22, 0x40};
uint32_t SDU_LEN = 2;
srslte::unique_byte_buffer_t sdu_buf = allocate_unique_buffer(*pool);
srslte::unique_byte_buffer_t pdu_buf = allocate_unique_buffer(*pool);
srslte::unique_byte_buffer_t sta_buf = allocate_unique_buffer(*pool);
if (not rlc.configure(srslte::rlc_config_t::default_rlc_am_config())) {
return -1;
}
// Write SDU into RLC entity
memcpy(sdu_buf->msg, &sdu[0], SDU_LEN);
sdu_buf->N_bytes = SDU_LEN;
sdu_buf->md.pdcp_sn = 10;
rlc.write_sdu(std::move(sdu_buf));
TESTASSERT(4 == rlc.get_buffer_state()); // 2 bytes for header + 2 bytes for payload
// Read 1 PDUs from RLC1 (4 bytes)
uint32_t len = rlc.read_pdu(pdu_buf->msg, 4);
pdu_buf->N_bytes = len;
TESTASSERT(0 == rlc.get_buffer_state());
// Feed ack to PDU
srslte::rlc_status_pdu_t s1;
s1.ack_sn = 1;
s1.N_nack = 0;
sta_buf->N_bytes = srslte::rlc_am_write_status_pdu(&s1, sta_buf->msg);
rlc.write_pdu(sta_buf->msg, sta_buf->N_bytes);
// Check PDCP notifications
TESTASSERT(pdcp.notified_counts.size() == 1);
TESTASSERT(pdcp.notified_counts.find(10) != pdcp.notified_counts.end());
TESTASSERT(pdcp.notified_counts[10] == 1);
return SRSLTE_SUCCESS;
}
// Test of a single SDU transmitted over 2 PDUs.
// Both PDUs are ACKed in the same status PDU.
int two_pdus_notify_test()
{
srslte::byte_buffer_pool* pool = srslte::byte_buffer_pool::get_instance();
pdcp_tester pdcp;
rrc_tester rrc;
srslte::timer_handler timers(8);
srslte::rlc_am_lte rlc(rlc_log, 1, &pdcp, &rrc, &timers);
uint8_t sdu[] = {0x22, 0x40, 0x30, 0x21, 0x50};
uint32_t SDU_LEN = 5;
srslte::unique_byte_buffer_t sdu_buf = allocate_unique_buffer(*pool);
srslte::unique_byte_buffer_t pdu1_buf = allocate_unique_buffer(*pool);
srslte::unique_byte_buffer_t pdu2_buf = allocate_unique_buffer(*pool);
srslte::unique_byte_buffer_t sta_buf = allocate_unique_buffer(*pool);
if (not rlc.configure(srslte::rlc_config_t::default_rlc_am_config())) {
return -1;
}
// Write SDU into RLC entity
memcpy(sdu_buf->msg, &sdu[0], SDU_LEN);
sdu_buf->N_bytes = SDU_LEN;
sdu_buf->md.pdcp_sn = 10;
rlc.write_sdu(std::move(sdu_buf));
TESTASSERT(7 == rlc.get_buffer_state()); // 2 bytes for header + 5 for payload
// Read first PDU from RLC1 (3 bytes of data)
pdu1_buf->N_bytes = rlc.read_pdu(pdu1_buf->msg, 5); // Read
TESTASSERT(4 == rlc.get_buffer_state()); // 2 bytes for header + 2 for payload
// Read second PDUs from RLC1 (3 bytes of data)
pdu2_buf->N_bytes = rlc.read_pdu(pdu2_buf->msg, 4); // 2 bytes for header + 2 for payload
TESTASSERT(0 == rlc.get_buffer_state());
// Feed ack of PDU1 to RLC
srslte::rlc_status_pdu_t s1;
s1.ack_sn = 1;
s1.N_nack = 0;
sta_buf->N_bytes = srslte::rlc_am_write_status_pdu(&s1, sta_buf->msg);
rlc.write_pdu(sta_buf->msg, sta_buf->N_bytes);
// Feed ack of PDU2 to RLC
srslte::rlc_status_pdu_t s2;
s2.ack_sn = 2;
s2.N_nack = 0;
sta_buf->N_bytes = srslte::rlc_am_write_status_pdu(&s2, sta_buf->msg);
rlc.write_pdu(sta_buf->msg, sta_buf->N_bytes);
// Check PDCP notifications
TESTASSERT(pdcp.notified_counts.size() == 1);
TESTASSERT(pdcp.notified_counts.find(10) != pdcp.notified_counts.end());
TESTASSERT(pdcp.notified_counts[10] == 1);
return SRSLTE_SUCCESS;
}
// Test of a two SDUs transmitted over a single PDU.
// Two SDUs -> K=1 (even number of LIs)
// The PDU is ACKed imediatly.
int two_sdus_notify_test()
{
srslte::byte_buffer_pool* pool = srslte::byte_buffer_pool::get_instance();
pdcp_tester pdcp;
rrc_tester rrc;
srslte::timer_handler timers(8);
srslte::rlc_am_lte rlc(rlc_log, 1, &pdcp, &rrc, &timers);
uint8_t sdu1[] = {0x22, 0x40, 0x30, 0x21, 0x50};
uint32_t SDU1_LEN = 5;
uint8_t sdu2[] = {0x22, 0x40};
uint32_t SDU2_LEN = 2;
srslte::unique_byte_buffer_t sdu1_buf = allocate_unique_buffer(*pool);
srslte::unique_byte_buffer_t sdu2_buf = allocate_unique_buffer(*pool);
srslte::unique_byte_buffer_t pdu_buf = allocate_unique_buffer(*pool);
srslte::unique_byte_buffer_t sta_buf = allocate_unique_buffer(*pool);
if (not rlc.configure(srslte::rlc_config_t::default_rlc_am_config())) {
return -1;
}
// Write SDU into RLC entity
memcpy(sdu1_buf->msg, &sdu1[0], SDU1_LEN);
sdu1_buf->N_bytes = SDU1_LEN;
sdu1_buf->md.pdcp_sn = 10;
rlc.write_sdu(std::move(sdu1_buf));
TESTASSERT(7 == rlc.get_buffer_state());
memcpy(sdu2_buf->msg, &sdu2[0], SDU2_LEN);
sdu2_buf->N_bytes = SDU2_LEN;
sdu2_buf->md.pdcp_sn = 13;
rlc.write_sdu(std::move(sdu2_buf));
TESTASSERT(11 == rlc.get_buffer_state()); // 2 bytes for header, 2 bytes for Li, and 7 for data
// Read PDU from RLC1 (7 bytes of data)
pdu_buf->N_bytes = rlc.read_pdu(pdu_buf->msg, 11); // 2 bytes for fixed header + 2 bytes for one LI
// + 7 bytes for payload
TESTASSERT(0 == rlc.get_buffer_state());
// Feed ack of PDU1 to RLC
srslte::rlc_status_pdu_t s1;
s1.ack_sn = 1;
s1.N_nack = 0;
sta_buf->N_bytes = srslte::rlc_am_write_status_pdu(&s1, sta_buf->msg);
rlc.write_pdu(sta_buf->msg, sta_buf->N_bytes);
// Check PDCP notifications
TESTASSERT(pdcp.notified_counts.size() == 2);
TESTASSERT(pdcp.notified_counts.find(10) != pdcp.notified_counts.end());
TESTASSERT(pdcp.notified_counts[10] == 1);
TESTASSERT(pdcp.notified_counts.find(13) != pdcp.notified_counts.end());
TESTASSERT(pdcp.notified_counts[13] == 1);
return SRSLTE_SUCCESS;
}
// Test of a three SDUs transmitted over a single PDU.
// The PDU is ACKed imediatly.
int three_sdus_notify_test()
{
srslte::byte_buffer_pool* pool = srslte::byte_buffer_pool::get_instance();
pdcp_tester pdcp;
rrc_tester rrc;
srslte::timer_handler timers(8);
srslte::rlc_am_lte rlc(rlc_log, 1, &pdcp, &rrc, &timers);
uint8_t sdu1[] = {0x22, 0x40, 0x30, 0x21, 0x50};
uint32_t SDU1_LEN = 5;
uint8_t sdu2[] = {0x22, 0x40};
uint32_t SDU2_LEN = 2;
uint8_t sdu3[] = {0x22, 0x40, 0x00};
uint32_t SDU3_LEN = 3;
srslte::unique_byte_buffer_t sdu1_buf = allocate_unique_buffer(*pool);
srslte::unique_byte_buffer_t sdu2_buf = allocate_unique_buffer(*pool);
srslte::unique_byte_buffer_t sdu3_buf = allocate_unique_buffer(*pool);
srslte::unique_byte_buffer_t pdu_buf = allocate_unique_buffer(*pool);
srslte::unique_byte_buffer_t sta_buf = allocate_unique_buffer(*pool);
if (not rlc.configure(srslte::rlc_config_t::default_rlc_am_config())) {
return -1;
}
// Write SDU into RLC entity
memcpy(sdu1_buf->msg, &sdu1[0], SDU1_LEN);
sdu1_buf->N_bytes = SDU1_LEN;
sdu1_buf->md.pdcp_sn = 10;
rlc.write_sdu(std::move(sdu1_buf));
TESTASSERT(7 == rlc.get_buffer_state());
memcpy(sdu2_buf->msg, &sdu2[0], SDU2_LEN);
sdu2_buf->N_bytes = SDU2_LEN;
sdu2_buf->md.pdcp_sn = 13;
rlc.write_sdu(std::move(sdu2_buf));
memcpy(sdu3_buf->msg, &sdu3[0], SDU3_LEN);
sdu3_buf->N_bytes = SDU3_LEN;
sdu3_buf->md.pdcp_sn = 14;
rlc.write_sdu(std::move(sdu3_buf));
TESTASSERT(15 == rlc.get_buffer_state()); // 2 bytes for fixed header, 3 bytes for two LIs, 10 for data
// Read PDU from RLC1 (10 bytes of data)
pdu_buf->N_bytes = rlc.read_pdu(pdu_buf->msg, 15); // 2 bytes for fixed header + 5 bytes for three LIs
// + 10 bytes for payload
TESTASSERT(0 == rlc.get_buffer_state());
// Feed ack of PDU1 to RLC
srslte::rlc_status_pdu_t s1;
s1.ack_sn = 1;
s1.N_nack = 0;
sta_buf->N_bytes = srslte::rlc_am_write_status_pdu(&s1, sta_buf->msg);
rlc.write_pdu(sta_buf->msg, sta_buf->N_bytes);
// Check PDCP notifications
TESTASSERT(pdcp.notified_counts.size() == 3);
TESTASSERT(pdcp.notified_counts.find(10) != pdcp.notified_counts.end());
TESTASSERT(pdcp.notified_counts.find(13) != pdcp.notified_counts.end());
TESTASSERT(pdcp.notified_counts.find(14) != pdcp.notified_counts.end());
TESTASSERT(pdcp.notified_counts[10] == 1);
TESTASSERT(pdcp.notified_counts[13] == 1);
TESTASSERT(pdcp.notified_counts[14] == 1);
return SRSLTE_SUCCESS;
}
// Test notification of an RTXED SDU.
int rtxed_sdu_notify_test()
{
srslte::byte_buffer_pool* pool = srslte::byte_buffer_pool::get_instance();
pdcp_tester pdcp;
rrc_tester rrc;
srslte::timer_handler timers(8);
srslte::rlc_am_lte rlc(rlc_log, 1, &pdcp, &rrc, &timers);
uint8_t sdu[] = {0x22, 0x40, 0x30, 0x21, 0x50};
uint32_t SDU_LEN = 5;
srslte::unique_byte_buffer_t sdu_buf = allocate_unique_buffer(*pool);
srslte::unique_byte_buffer_t pdu_buf = allocate_unique_buffer(*pool);
srslte::unique_byte_buffer_t sta_buf = allocate_unique_buffer(*pool);
if (not rlc.configure(srslte::rlc_config_t::default_rlc_am_config())) {
return -1;
}
// Write SDU into RLC entity
memcpy(sdu_buf->msg, &sdu[0], SDU_LEN);
sdu_buf->N_bytes = SDU_LEN;
sdu_buf->md.pdcp_sn = 10;
rlc.write_sdu(std::move(sdu_buf));
TESTASSERT(7 == rlc.get_buffer_state());
// Read first PDU from RLC (5 bytes of data)
pdu_buf->N_bytes = rlc.read_pdu(pdu_buf->msg, 7); // 2 bytes for fixed header + 5 bytes for payload
TESTASSERT(0 == rlc.get_buffer_state());
// Feed Nack of PDU1 to RLC
srslte::rlc_status_pdu_t s1;
s1.ack_sn = 1;
s1.N_nack = 1;
s1.nacks[0].nack_sn = 0;
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(7 == rlc.get_buffer_state());
// Check PDCP notifications
TESTASSERT(pdcp.notified_counts.empty());
// Read rtxed PDU from RLC (5 bytes of data)
pdu_buf->N_bytes = rlc.read_pdu(pdu_buf->msg, 7); // 2 bytes for fixed header + 5 bytes for payload
TESTASSERT(0 == rlc.get_buffer_state());
// Feed ack of PDU1 to RLC
srslte::rlc_status_pdu_t s2;
s2.ack_sn = 1;
s2.N_nack = 0;
sta_buf->N_bytes = srslte::rlc_am_write_status_pdu(&s2, sta_buf->msg);
rlc.write_pdu(sta_buf->msg, sta_buf->N_bytes);
TESTASSERT(0 == rlc.get_buffer_state());
// Check PDCP notifications
TESTASSERT(pdcp.notified_counts.size() == 1);
TESTASSERT(pdcp.notified_counts.find(10) != pdcp.notified_counts.end());
TESTASSERT(pdcp.notified_counts[10] == 1);
return SRSLTE_SUCCESS;
}
// Test out of order ACK for SDU.
// Two sdus are transmitted, and ack arrives out of order
int two_sdus_out_of_order_ack_notify_test()
{
srslte::byte_buffer_pool* pool = srslte::byte_buffer_pool::get_instance();
pdcp_tester pdcp;
rrc_tester rrc;
srslte::timer_handler timers(8);
srslte::rlc_am_lte rlc(rlc_log, 1, &pdcp, &rrc, &timers);
uint8_t sdu[] = {0x22, 0x40, 0x30, 0x21, 0x50};
uint32_t SDU_LEN = 5;
srslte::unique_byte_buffer_t sdu_buf = allocate_unique_buffer(*pool);
srslte::unique_byte_buffer_t pdu1_buf = allocate_unique_buffer(*pool);
srslte::unique_byte_buffer_t pdu2_buf = allocate_unique_buffer(*pool);
srslte::unique_byte_buffer_t sta_buf = allocate_unique_buffer(*pool);
if (not rlc.configure(srslte::rlc_config_t::default_rlc_am_config())) {
return -1;
}
// Write SDU into RLC entity
memcpy(sdu_buf->msg, &sdu[0], SDU_LEN);
sdu_buf->N_bytes = SDU_LEN;
sdu_buf->md.pdcp_sn = 10;
rlc.write_sdu(std::move(sdu_buf));
TESTASSERT(7 == rlc.get_buffer_state()); // 2 bytes for header + 5 for payload
// Read first PDU from RLC1 (3 bytes of data)
pdu1_buf->N_bytes = rlc.read_pdu(pdu1_buf->msg, 5); // Read
TESTASSERT(4 == rlc.get_buffer_state()); // 2 bytes for header + 2 for payload
// Read second PDUs from RLC1 (3 bytes of data)
pdu2_buf->N_bytes = rlc.read_pdu(pdu2_buf->msg, 4); // 2 bytes for header + 2 for payload
TESTASSERT(0 == rlc.get_buffer_state());
// Feed ack of PDU1 to RLC
srslte::rlc_status_pdu_t s1;
s1.ack_sn = 1;
s1.N_nack = 0;
// Intentionally do not write first ack to RLC
// Feed ack of PDU2 to RLC
srslte::rlc_status_pdu_t s2;
s2.ack_sn = 2;
s2.N_nack = 0;
// Write second ack
sta_buf->N_bytes = srslte::rlc_am_write_status_pdu(&s2, sta_buf->msg);
rlc.write_pdu(sta_buf->msg, sta_buf->N_bytes);
// Check PDCP notifications
TESTASSERT(pdcp.notified_counts.size() == 1);
TESTASSERT(pdcp.notified_counts.find(10) != pdcp.notified_counts.end());
TESTASSERT(pdcp.notified_counts[10] == 1);
// Write first ack (out of order)
sta_buf->N_bytes = srslte::rlc_am_write_status_pdu(&s1, sta_buf->msg);
rlc.write_pdu(sta_buf->msg, sta_buf->N_bytes);
// Check PDCP notifications
TESTASSERT(pdcp.notified_counts.size() == 1);
TESTASSERT(pdcp.notified_counts.find(10) != pdcp.notified_counts.end());
TESTASSERT(pdcp.notified_counts[10] == 1);
return SRSLTE_SUCCESS;
}
// Test out-of-order ack of a single SDU transmitted over 2 PDUs.
int two_pdus_out_of_order_ack_notify_test()
{
srslte::byte_buffer_pool* pool = srslte::byte_buffer_pool::get_instance();
pdcp_tester pdcp;
rrc_tester rrc;
srslte::timer_handler timers(8);
srslte::rlc_am_lte rlc(rlc_log, 1, &pdcp, &rrc, &timers);
uint8_t sdu[] = {0x22, 0x40, 0x30, 0x21, 0x50};
uint32_t SDU_LEN = 5;
srslte::unique_byte_buffer_t sdu_buf = allocate_unique_buffer(*pool);
srslte::unique_byte_buffer_t pdu1_buf = allocate_unique_buffer(*pool);
srslte::unique_byte_buffer_t pdu2_buf = allocate_unique_buffer(*pool);
srslte::unique_byte_buffer_t sta_buf = allocate_unique_buffer(*pool);
if (not rlc.configure(srslte::rlc_config_t::default_rlc_am_config())) {
return -1;
}
// Write SDU into RLC entity
memcpy(sdu_buf->msg, &sdu[0], SDU_LEN);
sdu_buf->N_bytes = SDU_LEN;
sdu_buf->md.pdcp_sn = 10;
rlc.write_sdu(std::move(sdu_buf));
TESTASSERT(7 == rlc.get_buffer_state()); // 2 bytes for header + 5 for payload
// Read first PDU from RLC1 (3 bytes of data)
pdu1_buf->N_bytes = rlc.read_pdu(pdu1_buf->msg, 5); // Read
TESTASSERT(4 == rlc.get_buffer_state()); // 2 bytes for header + 2 for payload
// Read second PDUs from RLC1 (3 bytes of data)
pdu2_buf->N_bytes = rlc.read_pdu(pdu2_buf->msg, 4); // 2 bytes for header + 2 for payload
TESTASSERT(0 == rlc.get_buffer_state());
// Feed ack of PDU1 to RLC
srslte::rlc_status_pdu_t s1;
s1.ack_sn = 1;
s1.N_nack = 0;
sta_buf->N_bytes = srslte::rlc_am_write_status_pdu(&s1, sta_buf->msg);
rlc.write_pdu(sta_buf->msg, sta_buf->N_bytes);
// Feed ack of PDU2 to RLC
srslte::rlc_status_pdu_t s2;
s2.ack_sn = 2;
s2.N_nack = 0;
sta_buf->N_bytes = srslte::rlc_am_write_status_pdu(&s2, sta_buf->msg);
rlc.write_pdu(sta_buf->msg, sta_buf->N_bytes);
// Check PDCP notifications
TESTASSERT(pdcp.notified_counts.size() == 1);
TESTASSERT(pdcp.notified_counts.find(10) != pdcp.notified_counts.end());
TESTASSERT(pdcp.notified_counts[10] == 1);
return SRSLTE_SUCCESS;
}
int main(int argc, char** argv)
{
srslte::byte_buffer_pool::get_instance();
TESTASSERT(simple_sdu_notify_test() == SRSLTE_SUCCESS);
TESTASSERT(two_pdus_notify_test() == SRSLTE_SUCCESS);
TESTASSERT(two_sdus_notify_test() == SRSLTE_SUCCESS);
TESTASSERT(three_sdus_notify_test() == SRSLTE_SUCCESS);
TESTASSERT(rtxed_sdu_notify_test() == SRSLTE_SUCCESS);
TESTASSERT(two_sdus_out_of_order_ack_notify_test() == SRSLTE_SUCCESS);
srslte::byte_buffer_pool::cleanup();
return SRSLTE_SUCCESS;
}

@ -57,6 +57,7 @@ public:
void write_pdu_bcch_dlsch(unique_byte_buffer_t sdu) {} void write_pdu_bcch_dlsch(unique_byte_buffer_t sdu) {}
void write_pdu_pcch(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 write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t pdu) {}
void notify_delivery(uint32_t lcid, const std::vector<uint32_t>& tx_count) {}
// RRC interface // RRC interface
void max_retx_attempted() {} void max_retx_attempted() {}

@ -46,6 +46,7 @@ public:
} }
sdus[n_sdus++] = std::move(sdu); sdus[n_sdus++] = std::move(sdu);
} }
void notify_delivery(uint32_t lcid, const std::vector<uint32_t>& pdcp_sn) {}
void write_pdu_bcch_bch(unique_byte_buffer_t sdu) {} void write_pdu_bcch_bch(unique_byte_buffer_t sdu) {}
void write_pdu_bcch_dlsch(unique_byte_buffer_t sdu) {} void write_pdu_bcch_dlsch(unique_byte_buffer_t sdu) {}
void write_pdu_pcch(unique_byte_buffer_t sdu) {} void write_pdu_pcch(unique_byte_buffer_t sdu) {}

@ -308,21 +308,14 @@ private:
std::mt19937 mt19937; std::mt19937 mt19937;
std::uniform_real_distribution<float> real_dist; std::uniform_real_distribution<float> real_dist;
byte_buffer_pool* pool = nullptr; byte_buffer_pool* pool = nullptr;
}; };
class rlc_tester : public pdcp_interface_rlc, public rrc_interface_rlc, public thread class rlc_tester : public pdcp_interface_rlc, public rrc_interface_rlc, public thread
{ {
public: public:
rlc_tester(rlc_interface_pdcp* rlc_, std::string name_, stress_test_args_t args_, uint32_t lcid_) : rlc_tester(rlc_interface_pdcp* rlc_, std::string name_, stress_test_args_t args_, uint32_t lcid_) :
log("TEST"), log("TEST"), rlc(rlc_), run_enable(true), rx_pdus(), name(name_), args(args_), lcid(lcid_), thread("RLC_TESTER")
rlc(rlc_),
run_enable(true),
rx_pdus(),
name(name_),
args(args_),
lcid(lcid_),
thread("RLC_TESTER")
{ {
log.set_level(srslte::LOG_LEVEL_ERROR); log.set_level(srslte::LOG_LEVEL_ERROR);
log.set_hex_limit(LOG_HEX_LIMIT); log.set_hex_limit(LOG_HEX_LIMIT);
@ -351,6 +344,7 @@ public:
void write_pdu_bcch_dlsch(unique_byte_buffer_t sdu) {} void write_pdu_bcch_dlsch(unique_byte_buffer_t sdu) {}
void write_pdu_pcch(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 sdu) {} void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t sdu) {}
void notify_delivery(uint32_t lcid, const std::vector<uint32_t>& pdcp_sns) {}
// RRC interface // RRC interface
void max_retx_attempted() {} void max_retx_attempted() {}

@ -49,6 +49,7 @@ public:
void write_pdu_bcch_dlsch(unique_byte_buffer_t sdu) {} void write_pdu_bcch_dlsch(unique_byte_buffer_t sdu) {}
void write_pdu_pcch(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 sdu) { sdus.push_back(std::move(sdu)); } void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t sdu) { sdus.push_back(std::move(sdu)); }
void notify_delivery(uint32_t lcid, const std::vector<uint32_t>& pdcp_sns) {}
// RRC interface // RRC interface
void max_retx_attempted() {} void max_retx_attempted() {}

@ -57,8 +57,8 @@ public:
bool get_metrics(srsenb::stack_metrics_t* metrics) final; bool get_metrics(srsenb::stack_metrics_t* metrics) final;
// GW srsue stack_interface_gw dummy interface // GW srsue stack_interface_gw dummy interface
bool is_registered(){return true;}; bool is_registered() { return true; };
bool start_service_request(){return true;}; bool start_service_request() { return true; };
// PHY->MAC interface // PHY->MAC interface
int sf_indication(const uint32_t tti); int sf_indication(const uint32_t tti);

@ -32,6 +32,7 @@ public:
// pdcp_interface_rlc // pdcp_interface_rlc
void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) override; void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) override;
void notify_delivery(uint16_t rnti, uint32_t lcid, const std::vector<uint32_t>& pdcp_sn) override;
void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t sdu) {} void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t sdu) {}
// pdcp_interface_rrc // pdcp_interface_rrc

@ -40,6 +40,7 @@ public:
// pdcp_interface_rlc_nr // pdcp_interface_rlc_nr
void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu); void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu);
void notify_delivery(uint16_t rnti, uint32_t lcid, const std::vector<uint32_t>& tx_count);
void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t sdu) {} void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t sdu) {}
// pdcp_interface_rrc_nr // pdcp_interface_rrc_nr

@ -67,6 +67,7 @@ private:
{ {
public: public:
void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu); void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu);
void notify_delivery(uint32_t lcid, const std::vector<uint32_t>& tx_count);
void write_pdu_bcch_bch(srslte::unique_byte_buffer_t sdu); void write_pdu_bcch_bch(srslte::unique_byte_buffer_t sdu);
void write_pdu_bcch_dlsch(srslte::unique_byte_buffer_t sdu); void write_pdu_bcch_dlsch(srslte::unique_byte_buffer_t sdu);
void write_pdu_pcch(srslte::unique_byte_buffer_t sdu); void write_pdu_pcch(srslte::unique_byte_buffer_t sdu);

@ -63,6 +63,7 @@ private:
{ {
public: public:
void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu); void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu);
void notify_delivery(uint32_t lcid, const std::vector<uint32_t>& pdcp_sns);
void write_pdu_bcch_bch(srslte::unique_byte_buffer_t sdu); void write_pdu_bcch_bch(srslte::unique_byte_buffer_t sdu);
void write_pdu_bcch_dlsch(srslte::unique_byte_buffer_t sdu); void write_pdu_bcch_dlsch(srslte::unique_byte_buffer_t sdu);
void write_pdu_pcch(srslte::unique_byte_buffer_t sdu); void write_pdu_pcch(srslte::unique_byte_buffer_t sdu);

@ -20,9 +20,7 @@ using namespace asn1::rrc_nr;
namespace srsenb { namespace srsenb {
rrc_nr::rrc_nr(srslte::timer_handler* timers_) : rrc_nr::rrc_nr(srslte::timer_handler* timers_) :
m_log("RRC"), m_log("RRC"), pool(srslte::byte_buffer_pool::get_instance()), timers(timers_)
pool(srslte::byte_buffer_pool::get_instance()),
timers(timers_)
{} {}
void rrc_nr::init(const rrc_nr_cfg_t& cfg_, void rrc_nr::init(const rrc_nr_cfg_t& cfg_,

@ -139,6 +139,13 @@ void pdcp::write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t
} }
} }
void pdcp::notify_delivery(uint16_t rnti, uint32_t lcid, const std::vector<uint32_t>& pdcp_sns)
{
if (users.count(rnti)) {
users[rnti].pdcp->notify_delivery(lcid, pdcp_sns);
}
}
void pdcp::write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu, int pdcp_sn) void pdcp::write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu, int pdcp_sn)
{ {
if (users.count(rnti)) { if (users.count(rnti)) {

@ -16,9 +16,7 @@
namespace srsenb { namespace srsenb {
pdcp_nr::pdcp_nr(srslte::task_sched_handle task_sched_, const char* logname) : pdcp_nr::pdcp_nr(srslte::task_sched_handle task_sched_, const char* logname) :
task_sched(task_sched_), task_sched(task_sched_), m_log(logname), pool(srslte::byte_buffer_pool::get_instance())
m_log(logname),
pool(srslte::byte_buffer_pool::get_instance())
{} {}
void pdcp_nr::init(const pdcp_nr_args_t& args_, void pdcp_nr::init(const pdcp_nr_args_t& args_,
@ -102,6 +100,15 @@ void pdcp_nr::write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer
} }
} }
void pdcp_nr::notify_delivery(uint16_t rnti, uint32_t lcid, const std::vector<uint32_t>& pdcp_sns)
{
if (users.count(rnti)) {
users[rnti].pdcp->notify_delivery(lcid, pdcp_sns);
} else {
m_log->error("Can't notify Ack of PDU. RNTI=0x%X doesn't exist.\n", rnti);
}
}
void pdcp_nr::write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) void pdcp_nr::write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu)
{ {
if (users.count(rnti)) { if (users.count(rnti)) {

@ -268,6 +268,11 @@ void rlc::user_interface::write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t
} }
} }
void rlc::user_interface::notify_delivery(uint32_t lcid, const std::vector<uint32_t>& pdcp_sns)
{
pdcp->notify_delivery(rnti, lcid, pdcp_sns);
}
void rlc::user_interface::write_pdu_bcch_bch(srslte::unique_byte_buffer_t sdu) void rlc::user_interface::write_pdu_bcch_bch(srslte::unique_byte_buffer_t sdu)
{ {
ERROR("Error: Received BCCH from ue=%d", rnti); ERROR("Error: Received BCCH from ue=%d", rnti);

@ -207,4 +207,9 @@ std::string rlc_nr::user_interface::get_rb_name(uint32_t lcid)
return srslte::to_string(static_cast<srslte::rb_id_nr_t>(lcid)); return srslte::to_string(static_cast<srslte::rb_id_nr_t>(lcid));
} }
void rlc_nr::user_interface::notify_delivery(uint32_t lcid, const std::vector<uint32_t>& pdcp_sns)
{
m_pdcp->notify_delivery(rnti, lcid, pdcp_sns);
}
} // namespace srsenb } // namespace srsenb
Loading…
Cancel
Save