From e3c763eae89df9a69bb2d611238ef18f78de311f Mon Sep 17 00:00:00 2001 From: Etienne Dechamps Date: Sun, 21 Jul 2013 13:05:42 +0100 Subject: [PATCH] Introduce lightweight PMTU probe replies. When replying to a PMTU probe, tinc sends a packet with the same length as the PMTU probe itself, which is usually large (~1450 bytes). This is not necessary: the other node wants to know the size of the PMTU probes that have been received, but encoding this information as the actual reply length is probably the most inefficient way to do it. It doubles the bandwidth usage of the PMTU discovery process, and makes it less reliable since large packets are more likely to be dropped. This patch introduces a new PMTU probe reply type, encoded as type "2" in the first byte of the packet, that indicates that the length of the PMTU probe that is being replied to is encoded in the next two bytes of the packet. Thus reply packets are only 3 bytes long. (This also protects against very broken networks that drop very small packets - yes, I've seen it happen on a subnet of a national ISP - in such a case the PMTU probe replies will be dropped, and tinc won't enable UDP communication, which is a good thing.) Because legacy nodes won't understand type 2 probe replies, the minor protocol number is bumped to 3. Note that this also improves bandwidth estimation, as it is able to measure bandwidth in both directions independently (the node receiving the replies is measuring in the TX direction) and the use of smaller reply packets might decrease the influence of jitter. --- src/net_packet.c | 36 +++++++++++++++++++++++++++--------- src/protocol.h | 2 +- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/net_packet.c b/src/net_packet.c index 4bbb2d6f..d700fd6b 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -179,12 +179,20 @@ void send_mtu_probe(node_t *n) { } static void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) { - logger(DEBUG_TRAFFIC, LOG_INFO, "Got MTU probe length %d from %s (%s)", packet->len, n->name, n->hostname); - if(!packet->data[0]) { + logger(DEBUG_TRAFFIC, LOG_INFO, "Got MTU probe request %d from %s (%s)", packet->len, n->name, n->hostname); + /* It's a probe request, send back a reply */ - packet->data[0] = 1; + /* Type 2 probe replies were introduced in protocol 17.3 */ + if ((n->options >> 24) == 3) { + uint8_t* data = packet->data; + *data++ = 2; + uint16_t len16 = htons(len); memcpy(data, &len16, 2); data += 2; + } else { + /* Legacy protocol: n won't understand type 2 probe replies. */ + packet->data[0] = 1; + } /* Temporarily set udp_confirmed, so that the reply is sent back exactly the way it came in. */ @@ -194,6 +202,16 @@ static void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) { send_udppacket(n, packet); n->status.udp_confirmed = udp_confirmed; } else { + length_t probelen = len; + if (packet->data[0] == 2) { + if (len < 3) + logger(DEBUG_TRAFFIC, LOG_WARNING, "Received invalid (too short) MTU probe reply from %s (%s)", n->name, n->hostname); + else { + uint16_t probelen16; memcpy(&probelen16, packet->data + 1, 2); probelen = ntohs(probelen16); + } + } + logger(DEBUG_TRAFFIC, LOG_INFO, "Got type %d MTU probe reply %d from %s (%s)", packet->data[0], probelen, n->name, n->hostname); + /* It's a valid reply: now we know bidirectional communication is possible using the address and socket that the reply packet used. */ @@ -203,7 +221,7 @@ static void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) { /* If we haven't established the PMTU yet, restart the discovery process. */ if(n->mtuprobes > 30) { - if (len == n->maxmtu + 8) { + if (probelen == n->maxmtu + 8) { logger(DEBUG_TRAFFIC, LOG_INFO, "Increase in PMTU to %s (%s) detected, restarting PMTU discovery", n->name, n->hostname); n->maxmtu = MTU; n->mtuprobes = 10; @@ -218,10 +236,10 @@ static void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) { /* If applicable, raise the minimum supported MTU */ - if(len > n->maxmtu) - len = n->maxmtu; - if(n->minmtu < len) - n->minmtu = len; + if(probelen > n->maxmtu) + probelen = n->maxmtu; + if(n->minmtu < probelen) + n->minmtu = probelen; /* Calculate RTT and bandwidth. The RTT is the time between the MTU probe burst was sent and the first @@ -238,7 +256,7 @@ static void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) { 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); + n->bandwidth = 2.0 * probelen / (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/protocol.h b/src/protocol.h index 93ef3f23..1a685554 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -26,7 +26,7 @@ /* Protocol version. Different major versions are incompatible. */ #define PROT_MAJOR 17 -#define PROT_MINOR 2 /* Should not exceed 255! */ +#define PROT_MINOR 3 /* Should not exceed 255! */ /* Silly Windows */ -- 2.20.1