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_ uint32_t packed_size_; ///< Stores the current packed size; sync on each change of nacks_
void refresh_packed_size(); void refresh_packed_size();
uint32_t nack_size(const rlc_status_nack_t& nack) const;
public: public:
rlc_am_nr_control_pdu_type_t cpt; ///< CPT header rlc_am_nr_control_pdu_type_t cpt; ///< CPT header
@ -99,6 +100,7 @@ public:
void push_nack(const rlc_status_nack_t& nack); void push_nack(const rlc_status_nack_t& nack);
const std::vector<rlc_status_nack_t>& get_nacks() const { return nacks_; } const std::vector<rlc_status_nack_t>& get_nacks() const { return nacks_; }
uint32_t get_packed_size() const { return packed_size; } 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(); 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 * - 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, * 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"); 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) { 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)) { if ((rx_window->has_sn(i) && (*rx_window)[i].fully_received)) {
// only update ACK_SN if this SN has been fully received RlcDebug("SDU SN=%d is fully received", i);
status->ack_sn = i;
RlcDebug("Updating ACK_SN. ACK_SN=%d", i);
} else { } else {
if (not rx_window->has_sn(i)) { if (not rx_window->has_sn(i)) {
// No segment received, NACK the whole SDU // 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 } // NACK loop
// make sure we don't exceed grant size (FIXME)
rlc_am_nr_write_status_pdu(*status, cfg.rx_sn_field_length, &tmp_buf);
}
/* /*
* - set the ACK_SN to the SN of the next not received RLC SDU which is not * - 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. * 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; 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) { if (max_len != UINT32_MAX) {
// UINT32_MAX is used just to query the status PDU length // 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; do_status = false;
} }
return tmp_buf.N_bytes;
return status->packed_size;
} }
uint32_t rlc_am_nr_rx::get_status_pdu_length() 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; uint32_t packed_size = rlc_am_nr_status_pdu_sizeof_header_ack_sn;
for (auto nack : nacks_) { 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 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; : rlc_am_nr_status_pdu_sizeof_nack_sn_ext_18bit_sn;
if (nack.has_so) { if (nack.has_so) {
packed_size += rlc_am_nr_status_pdu_sizeof_nack_so; result += rlc_am_nr_status_pdu_sizeof_nack_so;
} }
if (nack.has_nack_range) { if (nack.has_nack_range) {
packed_size += rlc_am_nr_status_pdu_sizeof_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) : 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) void rlc_am_nr_status_pdu_t::push_nack(const rlc_status_nack_t& nack)
{ {
nacks_.push_back(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 packed_size_ += nack_size(nack);
: 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; bool rlc_am_nr_status_pdu_t::trim(uint32_t max_packed_size)
} {
if (nack.has_nack_range) { if (max_packed_size >= packed_size_) {
packed_size_ += rlc_am_nr_status_pdu_sizeof_nack_range; // no trimming required
} return true;
}
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