[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openvpn-devel
Subject:    [Openvpn-devel] [PATCH 1/1] reliable: retransmit if 3 follow-up ACKs are received
From:       Max Fillinger <maximilian.fillinger () foxcrypto ! com>
Date:       2021-03-31 18:03:23
Message-ID: E1lRfW3-0001sy-VM () sfs-ml-4 ! v29 ! lw ! sourceforge ! com
[Download RAW message or body]

From: Steffan Karger <steffan.karger@fox-it.com>

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.
---
 src/openvpn/reliable.c | 20 +++++++++++++++++---
 src/openvpn/reliable.h |  7 +++++++
 2 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/src/openvpn/reliable.c b/src/openvpn/reliable.c
index 6c1f2da1..15b90fbe 100644
--- a/src/openvpn/reliable.c
+++ b/src/openvpn/reliable.c
@@ -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;
         }
diff --git a/src/openvpn/reliable.h b/src/openvpn/reliable.h
index a84d4290..97e6dce7 100644
--- a/src/openvpn/reliable.h
+++ b/src/openvpn/reliable.h
@@ -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;
 };
-- 
2.11.0



_______________________________________________
Openvpn-devel mailing list
Openvpn-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openvpn-devel


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic