Estimate RTT, bandwidth and packet loss between nodes.
authorGuus Sliepen <guus@tinc-vpn.org>
Wed, 16 Jan 2013 15:31:56 +0000 (16:31 +0100)
committerGuus Sliepen <guus@tinc-vpn.org>
Wed, 16 Jan 2013 15:31:56 +0000 (16:31 +0100)
Without adding any extra traffic, we can measure round trip times, estimate the
bandwidth and packet loss between nodes. The RTT and bandwidth can be measured
by timing the MTU probe packets. The RTT is the difference between the time a
burst of MTU probes was sent and when the first reply is received. The
bandwidth can be estimated by multiplying the size of the probe packets by the
time between succesive received probe replies of the same burst. The packet
loss can be estimated for incoming traffic by comparing how many packets have
actually been received to the increase in the sequence numbers.

The estimates are not perfect. Especially bandwidth is difficult to measure,
the only accurate way is to continuously send as much data as possible, but
that is obviously not desirable. The packet loss rate is also almost always
a few percent when sending a lot of data over the VPN via TCP, since TCP
*needs* packet loss to work properly.

src/net_packet.c
src/node.h

index c0be8c4..1e45543 100644 (file)
@@ -150,6 +150,21 @@ static void send_mtu_probe_handler(void *data) {
                send_udppacket(n, &packet);
        }
 
+       n->probe_counter = 0;
+       gettimeofday(&n->probe_time, NULL);
+
+       /* Calculate the packet loss of incoming traffic by comparing the rate of
+          packets received to the rate with which the sequence number has increased.
+        */
+
+       if(n->received > n->prev_received)
+               n->packetloss = 1.0 - (n->received - n->prev_received) / (float)(n->received_seqno - n->prev_received_seqno);
+       else
+               n->packetloss = n->received_seqno <= n->prev_received_seqno;
+
+       n->prev_received_seqno = n->received_seqno;
+       n->prev_received = n->received;
+
 end:
        timeout_set(&n->mtutimeout, &(struct timeval){timeout, rand() % 100000});
 }
@@ -196,6 +211,25 @@ static void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
                        len = n->maxmtu;
                if(n->minmtu < len)
                        n->minmtu = len;
+
+               /* Calculate RTT and bandwidth.
+                  The RTT is the time between the MTU probe burst was sent and the first
+                  reply is received. The bandwidth is measured using the time between the
+                  arrival of the first and third probe reply.
+                */
+
+               struct timeval now, diff;
+               gettimeofday(&now, NULL);
+               timersub(&now, &n->probe_time, &diff);
+               n->probe_counter++;
+
+               if(n->probe_counter == 1) {
+                       n->rtt = diff.tv_sec + diff.tv_usec * 1e-6;
+                       n->probe_time = now;
+               } else if(n->probe_counter == 3) {
+                       n->bandwidth = 2.0 * len / (diff.tv_sec + diff.tv_usec * 1e-6);
+                       logger(DEBUG_TRAFFIC, LOG_DEBUG, "%s (%s) RTT %.2f ms, burst bandwidth %.3f Mbit/s, rx packet loss %.2f %%", n->name, n->hostname, n->rtt * 1e3, n->bandwidth * 8e-6, n->packetloss * 1e2);
+               }
        }
 }
 
index 662ad68..51938cd 100644 (file)
@@ -78,6 +78,8 @@ typedef struct node_t {
        uint32_t sent_seqno;                    /* Sequence number last sent to this node */
        uint32_t received_seqno;                /* Sequence number last received from this node */
        uint32_t received;                      /* Total valid packets received from this node */
+       uint32_t prev_received_seqno;
+       uint32_t prev_received;
        uint32_t farfuture;                     /* Packets in a row that have arrived from the far future */
        unsigned char* late;                    /* Bitfield marking late packets */
 
@@ -86,6 +88,11 @@ typedef struct node_t {
        length_t maxmtu;                        /* Probed maximum MTU */
        int mtuprobes;                          /* Number of probes */
        timeout_t mtutimeout;                   /* Probe event */
+       struct timeval probe_time;              /* Time the last probe was sent or received */
+       int probe_counter;                      /* Number of probes received since last burst was sent */
+       float rtt;                              /* Last measured round trip time */
+       float bandwidth;                        /* Last measured bandwidth */
+       float packetloss;                       /* Last measured packet loss rate */
 
        uint64_t in_packets;
        uint64_t in_bytes;