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 #endif
e->active = false; 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) if (e->active)
{ {
++n_active; ++n_active;
if (now >= e->next_try) if (now >= e->next_try || e->n_acks >= N_ACK_RETRANSMIT)
{ {
++n_current; ++n_current;
} }
@ -581,7 +588,12 @@ reliable_send(struct reliable *rel, int *opcode)
for (i = 0; i < rel->size; ++i) for (i = 0; i < rel->size; ++i)
{ {
struct reliable_entry *e = &rel->array[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)) 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 */ /* constant timeout, no backoff */
best->next_try = local_now + best->timeout; best->next_try = local_now + best->timeout;
#endif #endif
best->n_acks = 0;
*opcode = best->opcode; *opcode = best->opcode;
dmsg(D_REL_DEBUG, "ACK reliable_send ID " packet_id_format " (size=%d to=%d)", 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, (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->opcode = opcode;
e->next_try = 0; e->next_try = 0;
e->timeout = 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); dmsg(D_REL_DEBUG, "ACK mark active incoming ID " packet_id_format, (packet_id_print_type)e->packet_id);
return; return;
} }

View File

@ -52,6 +52,10 @@
* the reliability layer for one VPN * the reliability layer for one VPN
* tunnel in one direction can store. */ * 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 * The acknowledgment structure in which packet IDs are stored for later
* acknowledgment. * acknowledgment.
@ -72,6 +76,9 @@ struct reliable_entry
interval_t timeout; interval_t timeout;
time_t next_try; time_t next_try;
packet_id_type packet_id; 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; int opcode;
struct buffer buf; struct buffer buf;
}; };