Commit 86e9e0c4 authored by Juliusz Chroboczek's avatar Juliusz Chroboczek

Merge branch 'rtt-metric-for-merge'

Conflicts:
	CHANGES
parents 81934a11 67e54a2b
babeld-1.5.0 (unreleased)
* Added support for an RTT-based metric -- see the description of
"enable-timestamps" in the manual page. This work was done by
Baptiste Jonglez with help from Matthieu Boutier.
15 November 2013: babeld-1.4.3 15 November 2013: babeld-1.4.3
* Added random-id option to config file (equivalent to -r). * Added random-id option to config file (equivalent to -r).
......
...@@ -148,13 +148,13 @@ main(int argc, char **argv) ...@@ -148,13 +148,13 @@ main(int argc, char **argv)
goto usage; goto usage;
break; break;
case 'h': case 'h':
default_wireless_hello_interval = parse_msec(optarg); default_wireless_hello_interval = parse_thousands(optarg);
if(default_wireless_hello_interval <= 0 || if(default_wireless_hello_interval <= 0 ||
default_wireless_hello_interval > 0xFFFF * 10) default_wireless_hello_interval > 0xFFFF * 10)
goto usage; goto usage;
break; break;
case 'H': case 'H':
default_wired_hello_interval = parse_msec(optarg); default_wired_hello_interval = parse_thousands(optarg);
if(default_wired_hello_interval <= 0 || if(default_wired_hello_interval <= 0 ||
default_wired_hello_interval > 0xFFFF * 10) default_wired_hello_interval > 0xFFFF * 10)
goto usage; goto usage;
...@@ -1052,12 +1052,15 @@ dump_tables(FILE *out) ...@@ -1052,12 +1052,15 @@ dump_tables(FILE *out)
fprintf(out, "My id %s seqno %d\n", format_eui64(myid), myseqno); fprintf(out, "My id %s seqno %d\n", format_eui64(myid), myseqno);
FOR_ALL_NEIGHBOURS(neigh) { FOR_ALL_NEIGHBOURS(neigh) {
fprintf(out, "Neighbour %s dev %s reach %04x rxcost %d txcost %d chan %d%s.\n", fprintf(out, "Neighbour %s dev %s reach %04x rxcost %d txcost %d "
"rtt %s rttcost %d chan %d%s.\n",
format_address(neigh->address), format_address(neigh->address),
neigh->ifp->name, neigh->ifp->name,
neigh->reach, neigh->reach,
neighbour_rxcost(neigh), neighbour_rxcost(neigh),
neigh->txcost, neigh->txcost,
format_thousands(neigh->rtt),
neighbour_rttcost(neigh),
neigh->ifp->channel, neigh->ifp->channel,
if_up(neigh->ifp) ? "" : " (down)"); if_up(neigh->ifp) ? "" : " (down)");
} }
......
...@@ -329,6 +329,40 @@ This defines the interval between full routing table dumps sent on this ...@@ -329,6 +329,40 @@ This defines the interval between full routing table dumps sent on this
interface; since Babel uses triggered updates and doesn't count to interface; since Babel uses triggered updates and doesn't count to
infinity, this can be set to a fairly large value, unless significant infinity, this can be set to a fairly large value, unless significant
packet loss is expected. The default is four times the hello interval. packet loss is expected. The default is four times the hello interval.
.TP
.BR enable\-timestamps " {" true | false }
Enable sending timestamps with each Hello and IHU message in order to
compute RTT values. The default is
.BR false .
.TP
.BI rtt\-exponential\-decay " decay"
This specifies the decay factor for the exponential moving average of
RTT samples, in units of 1/256. Must be between 1 and 256, inclusive.
Higher values discard old samples faster. The default is
.BR 42 .
.TP
.BI rtt\-min " rtt"
This specifies the minimum RTT, in milliseconds, starting from which
we increase the cost to a neighbour. The additional cost is linear in
(rtt -
.BR rtt\-min ).
The default is
.B 10
ms.
.TP
.BI rtt\-max " rtt"
This specifies the maximum RTT, in milliseconds, above which we don't
increase the cost to a neighbour. The default is
.B 120
ms.
.TP
.BI max\-rtt\-penalty " cost"
This specifies the maximum cost added to a neighbour because of RTT,
i.e. when the RTT is higher or equal than
.BR rtt\-max .
The default is
.BR 0 ,
which effectively disables the use of a RTT-based cost.
.SS Filtering rules .SS Filtering rules
A filtering rule is defined by a single line with the following format: A filtering rule is defined by a single line with the following format:
.IP .IP
......
...@@ -148,14 +148,14 @@ getint(int c, int *int_r, gnc_t gnc, void *closure) ...@@ -148,14 +148,14 @@ getint(int c, int *int_r, gnc_t gnc, void *closure)
} }
static int static int
getmsec(int c, int *int_r, gnc_t gnc, void *closure) getthousands(int c, int *int_r, gnc_t gnc, void *closure)
{ {
char *t; char *t;
int i; int i;
c = getword(c, &t, gnc, closure); c = getword(c, &t, gnc, closure);
if(c < -1) if(c < -1)
return c; return c;
i = parse_msec(t); i = parse_thousands(t);
if(i < 0) { if(i < 0) {
free(t); free(t);
return -2; return -2;
...@@ -408,13 +408,13 @@ parse_anonymous_ifconf(int c, gnc_t gnc, void *closure, ...@@ -408,13 +408,13 @@ parse_anonymous_ifconf(int c, gnc_t gnc, void *closure,
if_conf->cost = cost; if_conf->cost = cost;
} else if(strcmp(token, "hello-interval") == 0) { } else if(strcmp(token, "hello-interval") == 0) {
int interval; int interval;
c = getmsec(c, &interval, gnc, closure); c = getthousands(c, &interval, gnc, closure);
if(c < -1 || interval <= 0 || interval > 10 * 0xFFFF) if(c < -1 || interval <= 0 || interval > 10 * 0xFFFF)
goto error; goto error;
if_conf->hello_interval = interval; if_conf->hello_interval = interval;
} else if(strcmp(token, "update-interval") == 0) { } else if(strcmp(token, "update-interval") == 0) {
int interval; int interval;
c = getmsec(c, &interval, gnc, closure); c = getthousands(c, &interval, gnc, closure);
if(c < -1 || interval <= 0 || interval > 10 * 0xFFFF) if(c < -1 || interval <= 0 || interval > 10 * 0xFFFF)
goto error; goto error;
if_conf->update_interval = interval; if_conf->update_interval = interval;
...@@ -464,6 +464,36 @@ parse_anonymous_ifconf(int c, gnc_t gnc, void *closure, ...@@ -464,6 +464,36 @@ parse_anonymous_ifconf(int c, gnc_t gnc, void *closure,
if((if_conf->channel < 1 || if_conf->channel > 255) && if((if_conf->channel < 1 || if_conf->channel > 255) &&
if_conf->channel != IF_CHANNEL_NONINTERFERING) if_conf->channel != IF_CHANNEL_NONINTERFERING)
goto error; goto error;
} else if(strcmp(token, "enable-timestamps") == 0) {
int v;
c = getbool(c, &v, gnc, closure);
if(c < -1)
goto error;
if_conf->enable_timestamps = v;
} else if(strcmp(token, "rtt-exponential-decay") == 0) {
int decay;
c = getint(c, &decay, gnc, closure);
if(c < -1 || decay <= 0 || decay > 256)
goto error;
if_conf->rtt_exponential_decay = decay;
} else if(strcmp(token, "rtt-min") == 0) {
int rtt;
c = getthousands(c, &rtt, gnc, closure);
if(c < -1 || rtt <= 0)
goto error;
if_conf->rtt_min = rtt;
} else if(strcmp(token, "rtt-max") == 0) {
int rtt;
c = getthousands(c, &rtt, gnc, closure);
if(c < -1 || rtt <= 0)
goto error;
if_conf->rtt_max = rtt;
} else if(strcmp(token, "max-rtt-penalty") == 0) {
int cost;
c = getint(c, &cost, gnc, closure);
if(c < -1 || cost <= 0 || cost > 0xFFFF)
goto error;
if_conf->max_rtt_penalty = cost;
} else { } else {
goto error; goto error;
} }
...@@ -544,6 +574,10 @@ merge_ifconf(struct interface_conf *dest, ...@@ -544,6 +574,10 @@ merge_ifconf(struct interface_conf *dest,
MERGE(lq); MERGE(lq);
MERGE(faraway); MERGE(faraway);
MERGE(channel); MERGE(channel);
MERGE(rtt_exponential_decay);
MERGE(rtt_min);
MERGE(rtt_max);
MERGE(max_rtt_penalty);
#undef MERGE #undef MERGE
} }
......
...@@ -293,6 +293,9 @@ interface_up(struct interface *ifp, int up) ...@@ -293,6 +293,9 @@ interface_up(struct interface *ifp, int up)
if(IF_CONF(ifp, faraway) == CONFIG_YES) if(IF_CONF(ifp, faraway) == CONFIG_YES)
ifp->flags |= IF_FARAWAY; ifp->flags |= IF_FARAWAY;
if(IF_CONF(ifp, enable_timestamps) == CONFIG_YES)
ifp->enable_timestamps = 1;
if(IF_CONF(ifp, hello_interval) > 0) if(IF_CONF(ifp, hello_interval) > 0)
ifp->hello_interval = IF_CONF(ifp, hello_interval); ifp->hello_interval = IF_CONF(ifp, hello_interval);
else if((ifp->flags & IF_WIRED)) else if((ifp->flags & IF_WIRED))
...@@ -305,6 +308,25 @@ interface_up(struct interface *ifp, int up) ...@@ -305,6 +308,25 @@ interface_up(struct interface *ifp, int up)
IF_CONF(ifp, update_interval) : IF_CONF(ifp, update_interval) :
ifp->hello_interval * 4; ifp->hello_interval * 4;
ifp->rtt_exponential_decay =
IF_CONF(ifp, rtt_exponential_decay) > 0 ?
IF_CONF(ifp, rtt_exponential_decay) : 42;
ifp->rtt_min =
IF_CONF(ifp, rtt_min) > 0 ?
IF_CONF(ifp, rtt_min) : 10000;
ifp->rtt_max =
IF_CONF(ifp, rtt_max) > 0 ?
IF_CONF(ifp, rtt_max) : 120000;
if(ifp->rtt_max <= ifp->rtt_min) {
fprintf(stderr,
"Uh, rtt-max is less than or equal to rtt-min (%d <= %d). "
"Setting it to %d.\n", ifp->rtt_max, ifp->rtt_min,
ifp->rtt_min + 10000);
ifp->rtt_max = ifp->rtt_min + 10000;
}
ifp->max_rtt_penalty = IF_CONF(ifp, max_rtt_penalty);
if(ifp->ll) if(ifp->ll)
free(ifp->ll); free(ifp->ll);
ifp->numll = 0; ifp->numll = 0;
......
...@@ -37,6 +37,11 @@ struct interface_conf { ...@@ -37,6 +37,11 @@ struct interface_conf {
char lq; char lq;
char faraway; char faraway;
int channel; int channel;
int enable_timestamps;
unsigned int rtt_exponential_decay;
unsigned int rtt_min;
unsigned int rtt_max;
unsigned int max_rtt_penalty;
struct interface_conf *next; struct interface_conf *next;
}; };
...@@ -72,7 +77,9 @@ struct interface { ...@@ -72,7 +77,9 @@ struct interface {
unsigned char (*ll)[16]; unsigned char (*ll)[16];
int buffered; int buffered;
int bufsize; int bufsize;
char have_buffered_hello; /* Relative position of the Hello message in the send buffer, or
(-1) if there is none. */
int buffered_hello;
char have_buffered_id; char have_buffered_id;
char have_buffered_nh; char have_buffered_nh;
char have_buffered_prefix; char have_buffered_prefix;
...@@ -89,6 +96,14 @@ struct interface { ...@@ -89,6 +96,14 @@ struct interface {
unsigned short hello_seqno; unsigned short hello_seqno;
unsigned hello_interval; unsigned hello_interval;
unsigned update_interval; unsigned update_interval;
int enable_timestamps;
/* A higher value means we forget old RTT samples faster. Must be
between 1 and 256, inclusive. */
unsigned int rtt_exponential_decay;
/* Parameters for computing the cost associated to RTT. */
unsigned int rtt_min;
unsigned int rtt_max;
unsigned int max_rtt_penalty;
}; };
#define IF_CONF(_ifp, _field) \ #define IF_CONF(_ifp, _field) \
......
...@@ -133,12 +133,20 @@ local_kind(int kind) ...@@ -133,12 +133,20 @@ local_kind(int kind)
static void static void
local_notify_neighbour_1(int s, struct neighbour *neigh, int kind) local_notify_neighbour_1(int s, struct neighbour *neigh, int kind)
{ {
char buf[512]; char buf[512], rttbuf[64];
int rc; int rc;
rttbuf[0] = '\0';
if(valid_rtt(neigh)) {
rc = snprintf(rttbuf, 64, " rtt %s rttcost %d",
format_thousands(neigh->rtt), neighbour_rttcost(neigh));
if(rc < 0 || rc >= 64)
rttbuf[0] = '\0';
}
rc = snprintf(buf, 512, rc = snprintf(buf, 512,
"%s neighbour %lx address %s " "%s neighbour %lx address %s "
"if %s reach %04x rxcost %d txcost %d cost %d\n", "if %s reach %04x rxcost %d txcost %d%s cost %d\n",
local_kind(kind), local_kind(kind),
/* Neighbours never move around in memory , so we can use the /* Neighbours never move around in memory , so we can use the
address as a unique identifier. */ address as a unique identifier. */
...@@ -148,6 +156,7 @@ local_notify_neighbour_1(int s, struct neighbour *neigh, int kind) ...@@ -148,6 +156,7 @@ local_notify_neighbour_1(int s, struct neighbour *neigh, int kind)
neigh->reach, neigh->reach,
neighbour_rxcost(neigh), neighbour_rxcost(neigh),
neighbour_txcost(neigh), neighbour_txcost(neigh),
rttbuf,
neighbour_cost(neigh)); neighbour_cost(neigh));
if(rc < 0 || rc >= 512) if(rc < 0 || rc >= 512)
......
...@@ -166,6 +166,93 @@ parse_route_attributes(const unsigned char *a, int alen, ...@@ -166,6 +166,93 @@ parse_route_attributes(const unsigned char *a, int alen,
} }
} }
static int
parse_hello_subtlv(const unsigned char *a, int alen, struct neighbour *neigh)
{
int type, len, i = 0, ret = 0;
while(i < alen) {
type = a[0];
if(type == SUBTLV_PAD1) {
i++;
continue;
}
if(i + 1 > alen) {
fprintf(stderr, "Received truncated sub-TLV on Hello message.\n");
return -1;
}
len = a[i + 1];
if(i + len > alen) {
fprintf(stderr, "Received truncated sub-TLV on Hello message.\n");
return -1;
}
if(type == SUBTLV_PADN) {
/* Nothing to do. */
} else if(type == SUBTLV_TIMESTAMP) {
if(len >= 4) {
DO_NTOHL(neigh->hello_send_us, a + i + 2);
neigh->hello_rtt_receive_time = now;
ret = 1;
} else {
fprintf(stderr,
"Received incorrect RTT sub-TLV on Hello message.\n");
}
} else {
fprintf(stderr, "Received unknown Hello sub-TLV type %d.\n", type);
}
i += len + 2;
}
return ret;
}
static int
parse_ihu_subtlv(const unsigned char *a, int alen,
unsigned int *hello_send_us,
unsigned int *hello_rtt_receive_time)
{
int type, len, i = 0, ret = 0;
while(i < alen) {
type = a[0];
if(type == SUBTLV_PAD1) {
i++;
continue;
}
if(i + 1 > alen) {
fprintf(stderr, "Received truncated sub-TLV on IHU message.\n");
return -1;
}
len = a[i + 1];
if(i + len > alen) {
fprintf(stderr, "Received truncated sub-TLV on IHU message.\n");
return -1;
}
if(type == SUBTLV_PADN) {
/* Nothing to do. */
} else if(type == SUBTLV_TIMESTAMP) {
if(len >= 8) {
DO_NTOHL(*hello_send_us, a + i + 2);
DO_NTOHL(*hello_rtt_receive_time, a + i + 6);
ret = 1;
}
else {
fprintf(stderr,
"Received incorrect RTT sub-TLV on IHU message.\n");
}
} else {
fprintf(stderr, "Received unknown IHU sub-TLV type %d.\n", type);
}
i += len + 2;
}
return ret;
}
static int static int
network_address(int ae, const unsigned char *a, unsigned int len, network_address(int ae, const unsigned char *a, unsigned int len,
unsigned char *a_r) unsigned char *a_r)
...@@ -193,6 +280,14 @@ parse_packet(const unsigned char *from, struct interface *ifp, ...@@ -193,6 +280,14 @@ parse_packet(const unsigned char *from, struct interface *ifp,
have_v4_nh = 0, have_v6_nh = 0; have_v4_nh = 0, have_v6_nh = 0;
unsigned char router_id[8], v4_prefix[16], v6_prefix[16], unsigned char router_id[8], v4_prefix[16], v6_prefix[16],
v4_nh[16], v6_nh[16]; v4_nh[16], v6_nh[16];
int have_hello_rtt = 0;
/* Content of the RTT sub-TLV on IHU messages. */
unsigned int hello_send_us = 0, hello_rtt_receive_time = 0;
if(ifp->enable_timestamps) {
/* We want to track exactly when we received this packet. */
gettime(&now);
}
if(!linklocal(from)) { if(!linklocal(from)) {
fprintf(stderr, "Received packet from non-local address %s.\n", fprintf(stderr, "Received packet from non-local address %s.\n",
...@@ -276,6 +371,11 @@ parse_packet(const unsigned char *from, struct interface *ifp, ...@@ -276,6 +371,11 @@ parse_packet(const unsigned char *from, struct interface *ifp,
if(interval > 0) if(interval > 0)
/* Multiply by 3/2 to allow hellos to expire. */ /* Multiply by 3/2 to allow hellos to expire. */
schedule_neighbours_check(interval * 15, 0); schedule_neighbours_check(interval * 15, 0);
/* Sub-TLV handling. */
if(len > 8) {
if(parse_hello_subtlv(message + 8, len - 6, neigh) > 0)
have_hello_rtt = 1;
}
} else if(type == MESSAGE_IHU) { } else if(type == MESSAGE_IHU) {
unsigned short txcost, interval; unsigned short txcost, interval;
unsigned char address[16]; unsigned char address[16];
...@@ -298,6 +398,10 @@ parse_packet(const unsigned char *from, struct interface *ifp, ...@@ -298,6 +398,10 @@ parse_packet(const unsigned char *from, struct interface *ifp,
if(interval > 0) if(interval > 0)
/* Multiply by 3/2 to allow neighbours to expire. */ /* Multiply by 3/2 to allow neighbours to expire. */
schedule_neighbours_check(interval * 45, 0); schedule_neighbours_check(interval * 45, 0);
/* RTT sub-TLV. */
if(len > 10 + rc)
parse_ihu_subtlv(message + 8 + rc, len - 6 - rc,
&hello_send_us, &hello_rtt_receive_time);
} }
} else if(type == MESSAGE_ROUTER_ID) { } else if(type == MESSAGE_ROUTER_ID) {
if(len < 10) { if(len < 10) {
...@@ -491,6 +595,44 @@ parse_packet(const unsigned char *from, struct interface *ifp, ...@@ -491,6 +595,44 @@ parse_packet(const unsigned char *from, struct interface *ifp,
message[0], message[1], format_address(from), ifp->name); message[0], message[1], format_address(from), ifp->name);
goto done; goto done;
} }
/* We can calculate the RTT to this neighbour. */
if(have_hello_rtt && hello_send_us && hello_rtt_receive_time) {
int remote_waiting_us, local_waiting_us;
unsigned int rtt, smoothed_rtt;
unsigned int old_rttcost;
int changed = 0;
remote_waiting_us = neigh->hello_send_us - hello_rtt_receive_time;
local_waiting_us = time_us(neigh->hello_rtt_receive_time) -
hello_send_us;
/* Sanity checks (validity window of 10 minutes). */
if(remote_waiting_us < 0 || local_waiting_us < 0 ||
remote_waiting_us > 600000000 || local_waiting_us > 600000000)
return;
rtt = MAX(0, local_waiting_us - remote_waiting_us);
debugf("RTT to %s on %s sample result: %d us.\n",
format_address(from), ifp->name, rtt);
old_rttcost = neighbour_rttcost(neigh);
if (valid_rtt(neigh)) {
/* Running exponential average. */
smoothed_rtt = (ifp->rtt_exponential_decay * rtt
+ (256 - ifp->rtt_exponential_decay) * neigh->rtt);
/* Rounding (up or down) to get closer to the sample. */
neigh->rtt = (neigh->rtt >= rtt) ? smoothed_rtt / 256 :
(smoothed_rtt + 255) / 256;
} else {
/* We prefer to be conservative with new neighbours
(higher RTT) */
assert(rtt <= 0x7FFFFFFF);
neigh->rtt = 2*rtt;
}
changed = (neighbour_rttcost(neigh) == old_rttcost ? 0 : 1);
update_neighbour_metric(neigh, changed);
neigh->rtt_time = now;
}
return; return;
} }
...@@ -519,6 +661,29 @@ check_bucket(struct interface *ifp) ...@@ -519,6 +661,29 @@ check_bucket(struct interface *ifp)
} }
} }
static int
fill_rtt_message(struct interface *ifp)
{
if(ifp->enable_timestamps && (ifp->buffered_hello >= 0)) {
if(ifp->sendbuf[ifp->buffered_hello + 8] == SUBTLV_PADN &&
ifp->sendbuf[ifp->buffered_hello + 9] == 4) {
unsigned int time;
/* Change the type of sub-TLV. */
ifp->sendbuf[ifp->buffered_hello + 8] = SUBTLV_TIMESTAMP;
gettime(&now);
time = time_us(now);
DO_HTONL(ifp->sendbuf + ifp->buffered_hello + 10, time);
return 1;
} else {
fprintf(stderr,
"No space left for timestamp sub-TLV "
"(this shouldn't happen)\n");
return -1;
}
}
return 0;
}
void void
flushbuf(struct interface *ifp) flushbuf(struct interface *ifp)
{ {
...@@ -539,6 +704,7 @@ flushbuf(struct interface *ifp) ...@@ -539,6 +704,7 @@ flushbuf(struct interface *ifp)
sin6.sin6_port = htons(protocol_port); sin6.sin6_port = htons(protocol_port);
sin6.sin6_scope_id = ifp->ifindex; sin6.sin6_scope_id = ifp->ifindex;
DO_HTONS(packet_header + 2, ifp->buffered); DO_HTONS(packet_header + 2, ifp->buffered);
fill_rtt_message(ifp);
rc = babel_send(protocol_socket, rc = babel_send(protocol_socket,
packet_header, sizeof(packet_header), packet_header, sizeof(packet_header),
ifp->sendbuf, ifp->buffered, ifp->sendbuf, ifp->buffered,
...@@ -552,7 +718,7 @@ flushbuf(struct interface *ifp) ...@@ -552,7 +718,7 @@ flushbuf(struct interface *ifp)
} }
VALGRIND_MAKE_MEM_UNDEFINED(ifp->sendbuf, ifp->bufsize); VALGRIND_MAKE_MEM_UNDEFINED(ifp->sendbuf, ifp->bufsize);
ifp->buffered = 0; ifp->buffered = 0;
ifp->have_buffered_hello = 0; ifp->buffered_hello = -1;
ifp->have_buffered_id = 0; ifp->have_buffered_id = 0;
ifp->have_buffered_nh = 0; ifp->have_buffered_nh = 0;
ifp->have_buffered_prefix = 0; ifp->have_buffered_prefix = 0;
...@@ -632,6 +798,13 @@ accumulate_short(struct interface *ifp, unsigned short value) ...@@ -632,6 +798,13 @@ accumulate_short(struct interface *ifp, unsigned short value)
ifp->buffered += 2; ifp->buffered += 2;
} }
static void
accumulate_int(struct interface *ifp, unsigned int value)
{
DO_HTONL(ifp->sendbuf + ifp->buffered, value);
ifp->buffered += 4;
}
static void static void
accumulate_bytes(struct interface *ifp, accumulate_bytes(struct interface *ifp,
const unsigned char *value, unsigned len) const unsigned char *value, unsigned len)
...@@ -685,6 +858,13 @@ accumulate_unicast_short(struct neighbour *neigh, unsigned short value) ...@@ -685,6 +858,13 @@ accumulate_unicast_short(struct neighbour *neigh, unsigned short value)
unicast_buffered += 2; unicast_buffered += 2;
} }
static void
accumulate_unicast_int(struct neighbour *neigh, unsigned int value)
{
DO_HTONL(unicast_buffer + unicast_buffered, value);
unicast_buffered += 4;
}
static void static void
accumulate_unicast_bytes(struct neighbour *neigh, accumulate_unicast_bytes(struct neighbour *neigh,
const unsigned char *value, unsigned len) const unsigned char *value, unsigned len)
...@@ -711,7 +891,7 @@ send_hello_noupdate(struct interface *ifp, unsigned interval) ...@@ -711,7 +891,7 @@ send_hello_noupdate(struct interface *ifp, unsigned interval)
{ {
/* This avoids sending multiple hellos in a single packet, which breaks /* This avoids sending multiple hellos in a single packet, which breaks
link quality estimation. */ link quality estimation. */
if(ifp->have_buffered_hello) if(ifp->buffered_hello >= 0)
flushbuf(ifp); flushbuf(ifp);
ifp->hello_seqno = seqno_plus(ifp->hello_seqno, 1); ifp->hello_seqno = seqno_plus(ifp->hello_seqno, 1);
...@@ -723,12 +903,19 @@ send_hello_noupdate(struct interface *ifp, unsigned interval) ...@@ -723,12 +903,19 @@ send_hello_noupdate(struct interface *ifp, unsigned interval)
debugf("Sending hello %d (%d) to %s.\n", debugf("Sending hello %d (%d) to %s.\n",
ifp->hello_seqno, interval, ifp->name); ifp->hello_seqno, interval, ifp->name);
start_message(ifp, MESSAGE_HELLO, 6); start_message(ifp, MESSAGE_HELLO, ifp->enable_timestamps ? 12 : 6);
ifp->buffered_hello = ifp->buffered - 2;
accumulate_short(ifp, 0); accumulate_short(ifp, 0);
accumulate_short(ifp, ifp->hello_seqno); accumulate_short(ifp, ifp->hello_seqno);
accumulate_short(ifp, interval > 0xFFFF ? 0xFFFF : interval); accumulate_short(ifp, interval > 0xFFFF ? 0xFFFF : interval);
end_message(ifp, MESSAGE_HELLO, 6); if(ifp->enable_timestamps) {
ifp->have_buffered_hello = 1; /* Sub-TLV containing the local time of emission. We use a
Pad4 sub-TLV, which we'll fill just before sending. */
accumulate_byte(ifp, SUBTLV_PADN);
accumulate_byte(ifp, 4);
accumulate_int(ifp, 0);
}
end_message(ifp, MESSAGE_HELLO, ifp->enable_timestamps ? 12 : 6);
} }
void void
...@@ -764,6 +951,7 @@ flush_unicast(int dofree) ...@@ -764,6 +951,7 @@ flush_unicast(int dofree)
sin6.sin6_port = htons(protocol_port); sin6.sin6_port = htons(protocol_port);
sin6.sin6_scope_id = unicast_neighbour->ifp->ifindex; sin6.sin6_scope_id = unicast_neighbour->ifp->ifindex;
DO_HTONS(packet_header + 2, unicast_buffered); DO_HTONS(packet_header + 2, unicast_buffered);
fill_rtt_message(unicast_neighbour->ifp);
rc = babel_send(protocol_socket, rc = babel_send(protocol_socket,
packet_header, sizeof(packet_header), packet_header, sizeof(packet_header),
unicast_buffer, unicast_buffered, unicast_buffer, unicast_buffered,
...@@ -1206,6 +1394,8 @@ send_ihu(struct neighbour *neigh, struct interface *ifp) ...@@ -1206,6 +1394,8 @@ send_ihu(struct neighbour *neigh, struct interface *ifp)
{ {
int rxcost, interval; int rxcost, interval;
int ll; int ll;
int send_rtt_data;
int msglen;
if(neigh == NULL && ifp == NULL) { if(neigh == NULL && ifp == NULL) {
struct interface *ifp_aux; struct interface *ifp_aux;
...@@ -1249,8 +1439,21 @@ send_ihu(struct neighbour *neigh, struct interface *ifp) ...@@ -1249,8 +1439,21 @@ send_ihu(struct neighbour *neigh, struct interface *ifp)
ll = linklocal(neigh->address); ll = linklocal(neigh->address);
if(ifp->enable_timestamps && neigh->hello_send_us
/* Checks whether the RTT data is not too old to be sent. */
&& timeval_minus_msec(&now, &neigh->hello_rtt_receive_time) < 1000000) {
send_rtt_data = 1;
} else {
neigh->hello_send_us = 0;
send_rtt_data = 0;
}
/* The length depends on the format of the address, and then an
optional 10-bytes sub-TLV for timestamps (used to compute a RTT). */
msglen = (ll ? 14 : 22) + (send_rtt_data ? 10 : 0);
if(unicast_neighbour != neigh) { if(unicast_neighbour != neigh) {
start_message(ifp, MESSAGE_IHU, ll ? 14 : 22); start_message(ifp, MESSAGE_IHU, msglen);
accumulate_byte(ifp, ll ? 3 : 2); accumulate_byte(ifp, ll ? 3 : 2);
accumulate_byte(ifp, 0); accumulate_byte(ifp, 0);
accumulate_short(ifp, rxcost); accumulate_short(ifp, rxcost);
...@@ -1259,10 +1462,16 @@ send_ihu(struct neighbour *neigh, struct interface *ifp) ...@@ -1259,10 +1462,16 @@ send_ihu(struct neighbour *neigh, struct interface *ifp)
accumulate_bytes(ifp, neigh->address + 8, 8); accumulate_bytes(ifp, neigh->address + 8, 8);
else else
accumulate_bytes(ifp, neigh->address, 16); accumulate_bytes(ifp, neigh->address, 16);
end_message(ifp, MESSAGE_IHU, ll ? 14 : 22); if (send_rtt_data) {
accumulate_byte(ifp, SUBTLV_TIMESTAMP);
accumulate_byte(ifp, 8);
accumulate_int(ifp, neigh->hello_send_us);
accumulate_int(ifp, time_us(neigh->hello_rtt_receive_time));
}
end_message(ifp, MESSAGE_IHU, msglen);
} else { } else {
int rc; int rc;
rc = start_unicast_message(neigh, MESSAGE_IHU, ll ? 14 : 22); rc = start_unicast_message(neigh, MESSAGE_IHU, msglen);
if(rc < 0) return; if(rc < 0) return;
accumulate_unicast_byte(neigh, ll ? 3 : 2); accumulate_unicast_byte(neigh, ll ? 3 : 2);
accumulate_unicast_byte(neigh, 0); accumulate_unicast_byte(neigh, 0);
...@@ -1272,7 +1481,14 @@ send_ihu(struct neighbour *neigh, struct interface *ifp) ...@@ -1272,7 +1481,14 @@ send_ihu(struct neighbour *neigh, struct interface *ifp)
accumulate_unicast_bytes(neigh, neigh->address + 8, 8); accumulate_unicast_bytes(neigh, neigh->address + 8, 8);
else else
accumulate_unicast_bytes(neigh, neigh->address, 16); accumulate_unicast_bytes(neigh, neigh->address, 16);
end_unicast_message(neigh, MESSAGE_IHU, ll ? 14 : 22); if (send_rtt_data) {
accumulate_unicast_byte(neigh, SUBTLV_TIMESTAMP);
accumulate_unicast_byte(neigh, 8);
accumulate_unicast_int(neigh, neigh->hello_send_us);
accumulate_unicast_int(neigh,
time_us(neigh->hello_rtt_receive_time));
}
end_unicast_message(neigh, MESSAGE_IHU, msglen);
} }
} }
......
...@@ -44,6 +44,7 @@ THE SOFTWARE. ...@@ -44,6 +44,7 @@ THE SOFTWARE.
#define SUBTLV_PAD1 0 #define SUBTLV_PAD1 0
#define SUBTLV_PADN 1 #define SUBTLV_PADN 1
#define SUBTLV_DIVERSITY 2 /* Also known as babelz. */ #define SUBTLV_DIVERSITY 2 /* Also known as babelz. */
#define SUBTLV_TIMESTAMP 3 /* Used to compute RTT. */
extern unsigned short myseqno; extern unsigned short myseqno;
extern struct timeval seqno_time; extern struct timeval seqno_time;
......
...@@ -25,6 +25,7 @@ THE SOFTWARE. ...@@ -25,6 +25,7 @@ THE SOFTWARE.
#include <stdio.h> #include <stdio.h>
#include <sys/time.h> #include <sys/time.h>
#include <time.h> #include <time.h>
#include <assert.h>
#include "babeld.h" #include "babeld.h"
#include "util.h" #include "util.h"
...@@ -97,6 +98,10 @@ find_neighbour(const unsigned char *address, struct interface *ifp) ...@@ -97,6 +98,10 @@ find_neighbour(const unsigned char *address, struct interface *ifp)
neigh->hello_time = zero; neigh->hello_time = zero;
neigh->hello_interval = 0; neigh->hello_interval = 0;
neigh->ihu_interval = 0; neigh->ihu_interval = 0;
neigh->hello_send_us = 0;
neigh->hello_rtt_receive_time = zero;
neigh->rtt = 0;
neigh->rtt_time = zero;
neigh->ifp = ifp; neigh->ifp = ifp;
neigh->next = neighs; neigh->next = neighs;
neighs = neigh; neighs = neigh;
...@@ -293,10 +298,33 @@ neighbour_rxcost(struct neighbour *neigh) ...@@ -293,10 +298,33 @@ neighbour_rxcost(struct neighbour *neigh)
} }
} }
unsigned
neighbour_rttcost(struct neighbour *neigh)
{
struct interface *ifp = neigh->ifp;
if(!ifp->max_rtt_penalty || !valid_rtt(neigh))
return 0;
/* Function: linear behaviour between rtt_min and rtt_max. */
if(neigh->rtt <= ifp->rtt_min) {
return 0;
} else if(neigh->rtt <= ifp->rtt_max) {
unsigned long long tmp =
(unsigned long long)ifp->max_rtt_penalty *
(neigh->rtt - ifp->rtt_min) /
(ifp->rtt_max - ifp->rtt_min);
assert((tmp & 0x7FFFFFFF) == tmp);
return tmp;
} else {
return ifp->max_rtt_penalty;
}
}
unsigned unsigned
neighbour_cost(struct neighbour *neigh) neighbour_cost(struct neighbour *neigh)
{ {
unsigned a, b; unsigned a, b, cost;
if(!if_up(neigh->ifp)) if(!if_up(neigh->ifp))
return INFINITY; return INFINITY;
...@@ -311,7 +339,7 @@ neighbour_cost(struct neighbour *neigh) ...@@ -311,7 +339,7 @@ neighbour_cost(struct neighbour *neigh)
return INFINITY; return INFINITY;
if(!(neigh->ifp->flags & IF_LQ) || (a < 256 && b < 256)) { if(!(neigh->ifp->flags & IF_LQ) || (a < 256 && b < 256)) {
return a; cost = a;
} else { } else {
/* a = 256/alpha, b = 256/beta, where alpha and beta are the expected /* a = 256/alpha, b = 256/beta, where alpha and beta are the expected
probabilities of a packet getting through in the direct and reverse probabilities of a packet getting through in the direct and reverse
...@@ -320,6 +348,16 @@ neighbour_cost(struct neighbour *neigh) ...@@ -320,6 +348,16 @@ neighbour_cost(struct neighbour *neigh)
b = MAX(b, 256); b = MAX(b, 256);
/* 1/(alpha * beta), which is just plain ETX. */ /* 1/(alpha * beta), which is just plain ETX. */
/* Since a and b are capped to 16 bits, overflow is impossible. */ /* Since a and b are capped to 16 bits, overflow is impossible. */
return MIN((a * b + 128) >> 8, INFINITY); cost = (a * b + 128) >> 8;
} }
cost += neighbour_rttcost(neigh);
return MIN(cost, INFINITY);
}
int
valid_rtt(struct neighbour *neigh)
{
return (timeval_minus_msec(&now, &neigh->rtt_time) < 180000) ? 1 : 0;
} }
...@@ -31,6 +31,13 @@ struct neighbour { ...@@ -31,6 +31,13 @@ struct neighbour {
struct timeval ihu_time; struct timeval ihu_time;
unsigned short hello_interval; /* in centiseconds */ unsigned short hello_interval; /* in centiseconds */
unsigned short ihu_interval; /* in centiseconds */ unsigned short ihu_interval; /* in centiseconds */
/* Used for RTT estimation. */
/* Absolute time (modulo 2^32) at which the Hello was sent,
according to remote clock. */
unsigned int hello_send_us;
struct timeval hello_rtt_receive_time;
unsigned int rtt;
struct timeval rtt_time;
struct interface *ifp; struct interface *ifp;
}; };
...@@ -47,4 +54,6 @@ int update_neighbour(struct neighbour *neigh, int hello, int hello_interval); ...@@ -47,4 +54,6 @@ int update_neighbour(struct neighbour *neigh, int hello, int hello_interval);
unsigned check_neighbours(void); unsigned check_neighbours(void);
unsigned neighbour_txcost(struct neighbour *neigh); unsigned neighbour_txcost(struct neighbour *neigh);
unsigned neighbour_rxcost(struct neighbour *neigh); unsigned neighbour_rxcost(struct neighbour *neigh);
unsigned neighbour_rttcost(struct neighbour *neigh);
unsigned neighbour_cost(struct neighbour *neigh); unsigned neighbour_cost(struct neighbour *neigh);
int valid_rtt(struct neighbour *neigh);
...@@ -152,8 +152,10 @@ parse_nat(const char *string) ...@@ -152,8 +152,10 @@ parse_nat(const char *string)
return (int)l; return (int)l;
} }
/* Given a fixed-point string such as "42.1337", returns 1000 times
the value of the string, here 42133. */
int int
parse_msec(const char *string) parse_thousands(const char *string)
{ {
unsigned int in, fl; unsigned int in, fl;
int i, j; int i, j;
...@@ -293,6 +295,16 @@ format_eui64(const unsigned char *eui) ...@@ -293,6 +295,16 @@ format_eui64(const unsigned char *eui)
return buf[i]; return buf[i];
} }
const char *
format_thousands(unsigned int value)
{
static char buf[4][15];
static int i = 0;
i = (i + 1) % 4;
snprintf(buf[i], 15, "%d.%.3d", value / 1000, value % 1000);
return buf[i];
}
int int
parse_address(const char *address, unsigned char *addr_r, int *af_r) parse_address(const char *address, unsigned char *addr_r, int *af_r)
{ {
......
...@@ -66,6 +66,14 @@ seqno_plus(unsigned short s, int plus) ...@@ -66,6 +66,14 @@ seqno_plus(unsigned short s, int plus)
return ((s + plus) & 0xFFFF); return ((s + plus) & 0xFFFF);
} }
/* Returns a time in microseconds on 32 bits (thus modulo 2^32,
i.e. about 4295 seconds). */
static inline unsigned int
time_us(const struct timeval t)
{
return (unsigned int) (t.tv_sec * 1000000 + t.tv_usec);
}
int roughly(int value); int roughly(int value);
void timeval_minus(struct timeval *d, void timeval_minus(struct timeval *d,
const struct timeval *s1, const struct timeval *s2); const struct timeval *s1, const struct timeval *s2);
...@@ -78,7 +86,7 @@ int timeval_compare(const struct timeval *s1, const struct timeval *s2) ...@@ -78,7 +86,7 @@ int timeval_compare(const struct timeval *s1, const struct timeval *s2)
void timeval_min(struct timeval *d, const struct timeval *s); void timeval_min(struct timeval *d, const struct timeval *s);
void timeval_min_sec(struct timeval *d, time_t secs); void timeval_min_sec(struct timeval *d, time_t secs);
int parse_nat(const char *string) ATTRIBUTE ((pure)); int parse_nat(const char *string) ATTRIBUTE ((pure));
int parse_msec(const char *string) ATTRIBUTE ((pure)); int parse_thousands(const char *string) ATTRIBUTE ((pure));
void do_debugf(int level, const char *format, ...) void do_debugf(int level, const char *format, ...)
ATTRIBUTE ((format (printf, 2, 3))) COLD; ATTRIBUTE ((format (printf, 2, 3))) COLD;
int in_prefix(const unsigned char *restrict address, int in_prefix(const unsigned char *restrict address,
...@@ -90,6 +98,7 @@ unsigned char *mask_prefix(unsigned char *restrict ret, ...@@ -90,6 +98,7 @@ unsigned char *mask_prefix(unsigned char *restrict ret,
const char *format_address(const unsigned char *address); const char *format_address(const unsigned char *address);
const char *format_prefix(const unsigned char *address, unsigned char prefix); const char *format_prefix(const unsigned char *address, unsigned char prefix);
const char *format_eui64(const unsigned char *eui); const char *format_eui64(const unsigned char *eui);
const char *format_thousands(unsigned int value);
int parse_address(const char *address, unsigned char *addr_r, int *af_r); int parse_address(const char *address, unsigned char *addr_r, int *af_r);
int parse_net(const char *net, unsigned char *prefix_r, unsigned char *plen_r, int parse_net(const char *net, unsigned char *prefix_r, unsigned char *plen_r,
int *af_r); int *af_r);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment