lib,rlc_am_nr: truncate status PDUs if necessary

master
Robert Falkenberg 3 years ago
parent 489259dc78
commit 48dce0aab0

@ -87,6 +87,7 @@ private:
uint32_t packed_size_; ///< Stores the current packed size; sync on each change of nacks_
void refresh_packed_size();
uint32_t nack_size(const rlc_status_nack_t& nack) const;
public:
rlc_am_nr_control_pdu_type_t cpt; ///< CPT header
@ -99,6 +100,7 @@ public:
void push_nack(const rlc_status_nack_t& nack);
const std::vector<rlc_status_nack_t>& get_nacks() const { return nacks_; }
uint32_t get_packed_size() const { return packed_size; }
bool trim(uint32_t max_packed_size);
};
/****************************************************************************

@ -1414,8 +1414,6 @@ uint32_t rlc_am_nr_rx::get_status_pdu(rlc_am_nr_status_pdu_t* status, uint32_t m
status->reset();
byte_buffer_t tmp_buf;
/*
* - for the RLC SDUs with SN such that RX_Next <= SN < RX_Highest_Status that has not been completely
* received yet, in increasing SN order of RLC SDUs and increasing byte segment order within RLC SDUs,
@ -1425,9 +1423,7 @@ uint32_t rlc_am_nr_rx::get_status_pdu(rlc_am_nr_status_pdu_t* status, uint32_t m
RlcDebug("Generating status PDU");
for (uint32_t i = st.rx_next; rx_mod_base_nr(i) < rx_mod_base_nr(st.rx_highest_status); i = (i + 1) % mod_nr) {
if ((rx_window->has_sn(i) && (*rx_window)[i].fully_received)) {
// only update ACK_SN if this SN has been fully received
status->ack_sn = i;
RlcDebug("Updating ACK_SN. ACK_SN=%d", i);
RlcDebug("SDU SN=%d is fully received", i);
} else {
if (not rx_window->has_sn(i)) {
// No segment received, NACK the whole SDU
@ -1475,18 +1471,25 @@ uint32_t rlc_am_nr_rx::get_status_pdu(rlc_am_nr_status_pdu_t* status, uint32_t m
}
}
}
// TODO: add check to not exceed status->N_nack >= RLC_AM_NR_MAX_NACKS
// make sure we don't exceed grant size (FIXME)
rlc_am_nr_write_status_pdu(*status, cfg.rx_sn_field_length, &tmp_buf);
}
} // NACK loop
/*
* - set the ACK_SN to the SN of the next not received RLC SDU which is not
* indicated as missing in the resulting STATUS PDU.
*/
// FIXME as we do not check the size of status report, the next not received
// RLC SDU has the same SN as RX_HIGHEST_STATUS
status->ack_sn = st.rx_highest_status;
rlc_am_nr_write_status_pdu(*status, cfg.rx_sn_field_length, &tmp_buf);
// trim PDU if necessary
if (status->packed_size > max_len) {
RlcInfo("Trimming status PDU with %d NACKs and packed_size=%d into max_len=%d",
status->nacks.size(),
status->packed_size,
max_len);
log_rlc_am_nr_status_pdu_to_string(logger.debug, "Untrimmed status PDU - %s", status, rb_name);
if (not status->trim(max_len)) {
RlcError("Failed to trim status PDU into provided space: max_len=%d", max_len);
}
}
if (max_len != UINT32_MAX) {
// UINT32_MAX is used just to query the status PDU length
@ -1495,7 +1498,8 @@ uint32_t rlc_am_nr_rx::get_status_pdu(rlc_am_nr_status_pdu_t* status, uint32_t m
}
do_status = false;
}
return tmp_buf.N_bytes;
return status->packed_size;
}
uint32_t rlc_am_nr_rx::get_status_pdu_length()

@ -23,15 +23,21 @@ void rlc_am_nr_status_pdu_t::refresh_packed_size()
{
uint32_t packed_size = rlc_am_nr_status_pdu_sizeof_header_ack_sn;
for (auto nack : nacks_) {
packed_size += sn_size == rlc_am_nr_sn_size_t::size12bits ? rlc_am_nr_status_pdu_sizeof_nack_sn_ext_12bit_sn
: rlc_am_nr_status_pdu_sizeof_nack_sn_ext_18bit_sn;
if (nack.has_so) {
packed_size += rlc_am_nr_status_pdu_sizeof_nack_so;
}
if (nack.has_nack_range) {
packed_size += rlc_am_nr_status_pdu_sizeof_nack_range;
}
packed_size += nack_size(nack);
}
}
uint32_t rlc_am_nr_status_pdu_t::nack_size(const rlc_status_nack_t& nack) const
{
uint32_t result = sn_size == rlc_am_nr_sn_size_t::size12bits ? rlc_am_nr_status_pdu_sizeof_nack_sn_ext_12bit_sn
: rlc_am_nr_status_pdu_sizeof_nack_sn_ext_18bit_sn;
if (nack.has_so) {
result += rlc_am_nr_status_pdu_sizeof_nack_so;
}
if (nack.has_nack_range) {
result += rlc_am_nr_status_pdu_sizeof_nack_range;
}
return result;
}
rlc_am_nr_status_pdu_t::rlc_am_nr_status_pdu_t(rlc_am_nr_sn_size_t sn_size) :
@ -57,14 +63,31 @@ void rlc_am_nr_status_pdu_t::reset()
void rlc_am_nr_status_pdu_t::push_nack(const rlc_status_nack_t& nack)
{
nacks_.push_back(nack);
packed_size_ += sn_size == rlc_am_nr_sn_size_t::size12bits ? rlc_am_nr_status_pdu_sizeof_nack_sn_ext_12bit_sn
: rlc_am_nr_status_pdu_sizeof_nack_sn_ext_18bit_sn;
if (nack.has_so) {
packed_size_ += rlc_am_nr_status_pdu_sizeof_nack_so;
packed_size_ += nack_size(nack);
}
bool rlc_am_nr_status_pdu_t::trim(uint32_t max_packed_size)
{
if (max_packed_size >= packed_size_) {
// no trimming required
return true;
}
if (nack.has_nack_range) {
packed_size_ += rlc_am_nr_status_pdu_sizeof_nack_range;
if (max_packed_size <= rlc_am_nr_status_pdu_sizeof_header_ack_sn) {
// too little space for smallest possible status PDU (only header + ACK).
return false;
}
// remove NACKs (starting from the back) until it fits into given space
// note: when removing a NACK for a segment, we have to remove all other NACKs with the same SN as well,
// see TS 38.322 Sec. 5.3.4:
// "set the ACK_SN to the SN of the next not received RLC SDU
// which is not indicated as missing in the resulting STATUS PDU."
while (nacks_.size() > 0 && (max_packed_size >= packed_size_ || nacks_.back().nack_sn == ack_sn)) {
packed_size_ -= nack_size(nacks_.back());
ack_sn = nacks_.back().nack_sn;
nacks_.pop_back();
}
return true;
}
/****************************************************************************

Loading…
Cancel
Save