From 61275547cdf950e1c4499f19044ff171a9a74af7 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Wed, 16 Jan 2013 16:31:56 +0100 Subject: [PATCH] Estimate RTT, bandwidth and packet loss between nodes. 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 | 34 ++++++++++++++++++++++++++++++++++ src/node.h | 7 +++++++ 2 files changed, 41 insertions(+) diff --git a/src/net_packet.c b/src/net_packet.c index c0be8c4d..1e455434 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -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); + } } } diff --git a/src/node.h b/src/node.h index 662ad683..51938cd6 100644 --- a/src/node.h +++ b/src/node.h @@ -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; -- 2.39.5