0
0
mirror of https://github.com/OpenVPN/openvpn.git synced 2024-09-20 12:02:28 +02:00

reliable: retransmit if 3 follow-up ACKs are received

To improve the control channel performance under packet loss conditions,
add a more aggressive retransmit policy similar to what many TCP
implementations do: retransmit a packet if the ACK timeout expires (like
we already do), *or* if three ACKs for follow-up packets are received.

The rationale behind this is that if follow-up packets *are* received, the
connection is apparently functional and we should be able to retransmit
immediately. This significantly improves performance for connections with
low (up to a few percent) packet loss.
Acked-by: Arne Schwabe <arne@rfc2549.org>
Message-Id: <E1lRfW3-0001sy-VM@sfs-ml-4.v29.lw.sourceforge.com>
URL: https://www.mail-archive.com/search?l=mid&q=E1lRfW3-0001sy-VM@sfs-ml-4.v29.lw.sourceforge.com

Signed-off-by: Gert Doering <gert@greenie.muc.de>
This commit is contained in:
Steffan Karger 2021-03-31 20:03:23 +02:00 committed by Gert Doering
parent 343b61195b
commit 203afbe95e
2 changed files with 24 additions and 3 deletions

View File

@ -382,7 +382,14 @@ reliable_send_purge(struct reliable *rel, const struct reliable_ack *ack)
}
#endif
e->active = false;
break;
}
else if (e->active && e->packet_id < pid)
{
/* We have received an ACK for a packet with a higher PID. Either
* we have received ACKs out of or order or the packet has been
* lost. We count the number of ACKs to determine if we should
* resend it early. */
e->n_acks++;
}
}
}
@ -555,7 +562,7 @@ reliable_can_send(const struct reliable *rel)
if (e->active)
{
++n_active;
if (now >= e->next_try)
if (now >= e->next_try || e->n_acks >= N_ACK_RETRANSMIT)
{
++n_current;
}
@ -581,7 +588,12 @@ reliable_send(struct reliable *rel, int *opcode)
for (i = 0; i < rel->size; ++i)
{
struct reliable_entry *e = &rel->array[i];
if (e->active && local_now >= e->next_try)
/* If N_ACK_RETRANSMIT later packets have received ACKs, we assume
* that the packet was lost and resend it even if the timeout has
* not expired yet. */
if (e->active
&& (e->n_acks >= N_ACK_RETRANSMIT || local_now >= e->next_try))
{
if (!best || reliable_pid_min(e->packet_id, best->packet_id))
{
@ -599,6 +611,7 @@ reliable_send(struct reliable *rel, int *opcode)
/* constant timeout, no backoff */
best->next_try = local_now + best->timeout;
#endif
best->n_acks = 0;
*opcode = best->opcode;
dmsg(D_REL_DEBUG, "ACK reliable_send ID " packet_id_format " (size=%d to=%d)",
(packet_id_print_type)best->packet_id, best->buf.len,
@ -686,6 +699,7 @@ reliable_mark_active_incoming(struct reliable *rel, struct buffer *buf,
e->opcode = opcode;
e->next_try = 0;
e->timeout = 0;
e->n_acks = 0;
dmsg(D_REL_DEBUG, "ACK mark active incoming ID " packet_id_format, (packet_id_print_type)e->packet_id);
return;
}

View File

@ -52,6 +52,10 @@
* the reliability layer for one VPN
* tunnel in one direction can store. */
#define N_ACK_RETRANSMIT 3 /**< We retry sending a packet early if
* this many later packets have been
* ACKed. */
/**
* The acknowledgment structure in which packet IDs are stored for later
* acknowledgment.
@ -72,6 +76,9 @@ struct reliable_entry
interval_t timeout;
time_t next_try;
packet_id_type packet_id;
size_t n_acks; /* Number of acks received for packets with higher PID.
* Used for fast retransmission when there were at least
* N_ACK_RETRANSMIT. */
int opcode;
struct buffer buf;
};