Commit 3f8c8b73 authored by Cedric Roux's avatar Cedric Roux

nr rlc: change retx logic

When t_poll_retransmit expires we need to consider an SDU for
retransmission.

We used to take the first SDU (which could be a segment, not a full SDU)
of the wait list and put it in the retransmit list.

When testing with some UE (Amarisoft UE) a bad behavior was detected.

This is what happens for the SDU with SN 6 (for illustration purpose).

The gNB is sending an SDU in several pieces (it is segmented).

slot n:     rlc sn 6 [1 .. 119[   p=0   RECEIVED
slot n+x:   rlc sn 6 ]120 .. 180[ p=0   RECEIVED
slot n+x+y: rlc sn 6 ]181 .. 210] p=1   not RECEIVED

Then when t_poll_retransmit expires rlc retransmits only the PDU of
slot n (with p=1 this time) and the UE replies with ack 6. So nothing
happens on the gnb side.
(We would have expected ack 7 + nack 6 181..end.)

Then after t_poll_retransmit expires again rlc retransmits only PDU
of slot n and the UE still replies with ack 6.

This goes on forever (or some other timeout occurs.)

The logic is now changed.

When t_poll_retransmit expires we transfer all the SDUs in the wait list
having the same SN as the head of the wait list into the retransmit list.

Testing with Amarisoft UE, it seems to work properly.
parent 5b943f59
...@@ -1759,7 +1759,7 @@ static void check_t_poll_retransmit(nr_rlc_entity_am_t *entity) ...@@ -1759,7 +1759,7 @@ static void check_t_poll_retransmit(nr_rlc_entity_am_t *entity)
if (!check_poll_after_pdu_assembly(entity)) if (!check_poll_after_pdu_assembly(entity))
return; return;
/* retransmit the head of wait list, this is the case /* retransmit the SDU at the head of wait list, this is the case
* "consider any RLC SDU which has not been positively acknowledged for * "consider any RLC SDU which has not been positively acknowledged for
* retransmission" of 36.322 5.3.3.4. * retransmission" of 36.322 5.3.3.4.
* We don't search for the highest SN, it's simpler to just take the head * We don't search for the highest SN, it's simpler to just take the head
...@@ -1771,39 +1771,45 @@ static void check_t_poll_retransmit(nr_rlc_entity_am_t *entity) ...@@ -1771,39 +1771,45 @@ static void check_t_poll_retransmit(nr_rlc_entity_am_t *entity)
* It seems that no, the wait list should not be empty here, but not sure. * It seems that no, the wait list should not be empty here, but not sure.
*/ */
entity->wait_list = cur->next;
if (entity->wait_list == NULL)
entity->wait_end = NULL;
/* 38.322 says "SDU", not "SDU segment", but let's retransmit only
* the 'cur' SDU segment. To be changed if needed. (Maybe we have
* to retransmit all SDU segments with the same SN that are in the
* wait list.)
*/
/* increase retx count. Don't care about segmentation, so maybe we /* increase retx count. Don't care about segmentation, so maybe we
* increase too much. * increase too much.
*/ */
cur->sdu->retx_count++; cur->sdu->retx_count++;
/* report max RETX reached for all retx_count >= max_retx_threshold
* (specs say to report if retx_count == max_retx_threshold). int sdu_retx_count = cur->sdu->retx_count;
* Upper layers should react (radio link failure), so no big deal. int retransmit_sn = cur->sdu->sn;
* We deal with segmentation by requiring
* retx_count >= max_retx_threshold * number of segments. /* 38.322 says "SDU", not "SDU segment", so let's retransmit all
* We may report max RETX reached too late/early. To be refined if * SDU segments with the retransmit SN in the wait list.
* this is a problem.
*/ */
if (cur->sdu->retx_count do {
>= entity->max_retx_threshold * cur->sdu->ref_count) entity->wait_list = cur->next;
entity->common.max_retx_reached(entity->common.max_retx_reached_data, if (entity->wait_list == NULL)
(nr_rlc_entity_t *)entity); entity->wait_end = NULL;
/* update buffer status */ /* update buffer status */
entity->common.bstatus.retx_size += compute_pdu_header_size(entity, cur) entity->common.bstatus.retx_size += compute_pdu_header_size(entity, cur)
+ cur->size; + cur->size;
LOG_D(RLC, "put sn %d so %d size %d in retx list (retx_count %d)\n",
cur->sdu->sn, cur->so, cur->size, cur->sdu->retx_count);
/* put in retransmit list */ /* put in retransmit list */
entity->retransmit_list = nr_rlc_sdu_segment_list_add(sn_compare_tx, entity, entity->retransmit_list = nr_rlc_sdu_segment_list_add(sn_compare_tx, entity,
entity->retransmit_list, cur); entity->retransmit_list, cur);
cur = entity->wait_list;
} while (cur != NULL && cur->sdu->sn == retransmit_sn);
/* report max RETX reached for all retx_count >= max_retx_threshold
* (specs say to report if retx_count == max_retx_threshold).
* Upper layers should react (radio link failure), so no big deal.
* Because of segmentation, we may report too early/too late, not
* very clear. To refine if needed.
*/
if (sdu_retx_count >= entity->max_retx_threshold)
entity->common.max_retx_reached(entity->common.max_retx_reached_data,
(nr_rlc_entity_t *)entity);
} }
static void check_t_reassembly(nr_rlc_entity_am_t *entity) static void check_t_reassembly(nr_rlc_entity_am_t *entity)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment