[PATCH] rxrpc: Adjust retransmission backoff

Marc Dionne marc.dionne at auristor.com
Thu Jan 6 08:15:33 PST 2022


On Wed, Jan 5, 2022 at 7:13 AM David Howells <dhowells at redhat.com> wrote:
>
> Improve retransmission backoff by only backing off when we retransmit data
> packets rather than when we set the lost ack timer.
>
> To this end:
>
>  (1) In rxrpc_resend(), use rxrpc_get_rto_backoff() when setting the
>      retransmission timer and only tell it that we are retransmitting if we
>      actually have things to retransmit.
>
>      Note that it's possible for the retransmission algorithm to race with
>      the processing of a received ACK, so we may see no packets needing
>      retransmission.
>
>  (2) In rxrpc_send_data_packet(), don't bump the backoff when setting the
>      ack_lost_at timer, as it may then get bumped twice.
>
> With this, when looking at one particular packet, the retransmission
> intervals were seen to be 1.5ms, 2ms, 3ms, 5ms, 9ms, 17ms, 33ms, 71ms,
> 136ms, 264ms, 544ms, 1.088s, 2.1s, 4.2s and 8.3s.
>
> Suggested-by: Marc Dionne <marc.dionne at auristor.com>
> Signed-off-by: David Howells <dhowells at redhat.com>
> cc: linux-afs at lists.infradead.org
> ---
>
>  net/rxrpc/call_event.c |    8 +++-----
>  net/rxrpc/output.c     |    2 +-
>  2 files changed, 4 insertions(+), 6 deletions(-)
>
> diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c
> index 6be2672a65ea..df864e692267 100644
> --- a/net/rxrpc/call_event.c
> +++ b/net/rxrpc/call_event.c
> @@ -157,7 +157,7 @@ static void rxrpc_congestion_timeout(struct rxrpc_call *call)
>  static void rxrpc_resend(struct rxrpc_call *call, unsigned long now_j)
>  {
>         struct sk_buff *skb;
> -       unsigned long resend_at, rto_j;
> +       unsigned long resend_at;
>         rxrpc_seq_t cursor, seq, top;
>         ktime_t now, max_age, oldest, ack_ts;
>         int ix;
> @@ -165,10 +165,8 @@ static void rxrpc_resend(struct rxrpc_call *call, unsigned long now_j)
>
>         _enter("{%d,%d}", call->tx_hard_ack, call->tx_top);
>
> -       rto_j = call->peer->rto_j;
> -
>         now = ktime_get_real();
> -       max_age = ktime_sub(now, jiffies_to_usecs(rto_j));
> +       max_age = ktime_sub(now, jiffies_to_usecs(call->peer->rto_j));
>
>         spin_lock_bh(&call->lock);
>
> @@ -213,7 +211,7 @@ static void rxrpc_resend(struct rxrpc_call *call, unsigned long now_j)
>         }
>
>         resend_at = nsecs_to_jiffies(ktime_to_ns(ktime_sub(now, oldest)));
> -       resend_at += jiffies + rto_j;
> +       resend_at += jiffies + rxrpc_get_rto_backoff(call->peer, retrans);
>         WRITE_ONCE(call->resend_at, resend_at);
>
>         if (unacked)
> diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c
> index 10f2bf2e9068..a45c83f22236 100644
> --- a/net/rxrpc/output.c
> +++ b/net/rxrpc/output.c
> @@ -468,7 +468,7 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb,
>                         if (call->peer->rtt_count > 1) {
>                                 unsigned long nowj = jiffies, ack_lost_at;
>
> -                               ack_lost_at = rxrpc_get_rto_backoff(call->peer, retrans);
> +                               ack_lost_at = rxrpc_get_rto_backoff(call->peer, false);
>                                 ack_lost_at += nowj;
>                                 WRITE_ONCE(call->ack_lost_at, ack_lost_at);
>                                 rxrpc_reduce_call_timer(call, ack_lost_at, nowj,

That's identical (modulo debugging code) to what I tested to produce
the observed numbers in the commit message.
Much better than continuously resending every 2-3ms until a timeout
occurs, which resulted in thousands of resent packets.

Reviewed-by: Marc Dionne <marc.dionne at auristor.com>
Tested-by: Marc Dionne <marc.dionne at auristor.com>

Marc



More information about the linux-afs mailing list