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
* Added random-id option to config file (equivalent to -r).
......
......@@ -148,13 +148,13 @@ main(int argc, char **argv)
goto usage;
break;
case 'h':
default_wireless_hello_interval = parse_msec(optarg);
default_wireless_hello_interval = parse_thousands(optarg);
if(default_wireless_hello_interval <= 0 ||
default_wireless_hello_interval > 0xFFFF * 10)
goto usage;
break;
case 'H':
default_wired_hello_interval = parse_msec(optarg);
default_wired_hello_interval = parse_thousands(optarg);
if(default_wired_hello_interval <= 0 ||
default_wired_hello_interval > 0xFFFF * 10)
goto usage;
......@@ -1052,12 +1052,15 @@ dump_tables(FILE *out)
fprintf(out, "My id %s seqno %d\n", format_eui64(myid), myseqno);
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),
neigh->ifp->name,
neigh->reach,
neighbour_rxcost(neigh),
neigh->txcost,
format_thousands(neigh->rtt),
neighbour_rttcost(neigh),
neigh->ifp->channel,
if_up(neigh->ifp) ? "" : " (down)");
}
......
......@@ -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
infinity, this can be set to a fairly large value, unless significant
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
A filtering rule is defined by a single line with the following format:
.IP
......
......@@ -148,14 +148,14 @@ getint(int c, int *int_r, gnc_t gnc, void *closure)
}
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;
int i;
c = getword(c, &t, gnc, closure);
if(c < -1)
return c;
i = parse_msec(t);
i = parse_thousands(t);
if(i < 0) {
free(t);
return -2;
......@@ -408,13 +408,13 @@ parse_anonymous_ifconf(int c, gnc_t gnc, void *closure,
if_conf->cost = cost;
} else if(strcmp(token, "hello-interval") == 0) {
int interval;
c = getmsec(c, &interval, gnc, closure);
c = getthousands(c, &interval, gnc, closure);
if(c < -1 || interval <= 0 || interval > 10 * 0xFFFF)
goto error;
if_conf->hello_interval = interval;
} else if(strcmp(token, "update-interval") == 0) {
int interval;
c = getmsec(c, &interval, gnc, closure);
c = getthousands(c, &interval, gnc, closure);
if(c < -1 || interval <= 0 || interval > 10 * 0xFFFF)
goto error;
if_conf->update_interval = interval;
......@@ -464,6 +464,36 @@ parse_anonymous_ifconf(int c, gnc_t gnc, void *closure,
if((if_conf->channel < 1 || if_conf->channel > 255) &&
if_conf->channel != IF_CHANNEL_NONINTERFERING)
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 {
goto error;
}
......@@ -544,6 +574,10 @@ merge_ifconf(struct interface_conf *dest,
MERGE(lq);
MERGE(faraway);
MERGE(channel);
MERGE(rtt_exponential_decay);
MERGE(rtt_min);
MERGE(rtt_max);
MERGE(max_rtt_penalty);
#undef MERGE
}
......
......@@ -293,6 +293,9 @@ interface_up(struct interface *ifp, int up)
if(IF_CONF(ifp, faraway) == CONFIG_YES)
ifp->flags |= IF_FARAWAY;
if(IF_CONF(ifp, enable_timestamps) == CONFIG_YES)
ifp->enable_timestamps = 1;
if(IF_CONF(ifp, hello_interval) > 0)
ifp->hello_interval = IF_CONF(ifp, hello_interval);
else if((ifp->flags & IF_WIRED))
......@@ -305,6 +308,25 @@ interface_up(struct interface *ifp, int up)
IF_CONF(ifp, update_interval) :
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)
free(ifp->ll);
ifp->numll = 0;
......
......@@ -37,6 +37,11 @@ struct interface_conf {
char lq;
char faraway;
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;
};
......@@ -72,7 +77,9 @@ struct interface {
unsigned char (*ll)[16];
int buffered;
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_nh;
char have_buffered_prefix;
......@@ -89,6 +96,14 @@ struct interface {
unsigned short hello_seqno;
unsigned hello_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) \
......
......@@ -133,12 +133,20 @@ local_kind(int kind)
static void
local_notify_neighbour_1(int s, struct neighbour *neigh, int kind)
{
char buf[512];
char buf[512], rttbuf[64];
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,
"%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),
/* Neighbours never move around in memory , so we can use the
address as a unique identifier. */
......@@ -148,6 +156,7 @@ local_notify_neighbour_1(int s, struct neighbour *neigh, int kind)
neigh->reach,
neighbour_rxcost(neigh),
neighbour_txcost(neigh),
rttbuf,
neighbour_cost(neigh));
if(rc < 0 || rc >= 512)
......
......@@ -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
network_address(int ae, const unsigned char *a, unsigned int len,
unsigned char *a_r)
......@@ -193,6 +280,14 @@ parse_packet(const unsigned char *from, struct interface *ifp,
have_v4_nh = 0, have_v6_nh = 0;
unsigned char router_id[8], v4_prefix[16], v6_prefix[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)) {
fprintf(stderr, "Received packet from non-local address %s.\n",
......@@ -276,6 +371,11 @@ parse_packet(const unsigned char *from, struct interface *ifp,
if(interval > 0)
/* Multiply by 3/2 to allow hellos to expire. */
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) {
unsigned short txcost, interval;
unsigned char address[16];
......@@ -298,6 +398,10 @@ parse_packet(const unsigned char *from, struct interface *ifp,
if(interval > 0)
/* Multiply by 3/2 to allow neighbours to expire. */
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) {
if(len < 10) {
......@@ -491,6 +595,44 @@ parse_packet(const unsigned char *from, struct interface *ifp,
message[0], message[1], format_address(from), ifp->name);
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;
}
......@@ -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
flushbuf(struct interface *ifp)
{
......@@ -539,6 +704,7 @@ flushbuf(struct interface *ifp)
sin6.sin6_port = htons(protocol_port);
sin6.sin6_scope_id = ifp->ifindex;
DO_HTONS(packet_header + 2, ifp->buffered);
fill_rtt_message(ifp);
rc = babel_send(protocol_socket,
packet_header, sizeof(packet_header),
ifp->sendbuf, ifp->buffered,
......@@ -552,7 +718,7 @@ flushbuf(struct interface *ifp)
}
VALGRIND_MAKE_MEM_UNDEFINED(ifp->sendbuf, ifp->bufsize);
ifp->buffered = 0;
ifp->have_buffered_hello = 0;
ifp->buffered_hello = -1;
ifp->have_buffered_id = 0;
ifp->have_buffered_nh = 0;
ifp->have_buffered_prefix = 0;
......@@ -632,6 +798,13 @@ accumulate_short(struct interface *ifp, unsigned short value)
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
accumulate_bytes(struct interface *ifp,
const unsigned char *value, unsigned len)
......@@ -685,6 +858,13 @@ accumulate_unicast_short(struct neighbour *neigh, unsigned short value)
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
accumulate_unicast_bytes(struct neighbour *neigh,
const unsigned char *value, unsigned len)
......@@ -711,7 +891,7 @@ send_hello_noupdate(struct interface *ifp, unsigned interval)
{
/* This avoids sending multiple hellos in a single packet, which breaks
link quality estimation. */
if(ifp->have_buffered_hello)
if(ifp->buffered_hello >= 0)
flushbuf(ifp);
ifp->hello_seqno = seqno_plus(ifp->hello_seqno, 1);
......@@ -723,12 +903,19 @@ send_hello_noupdate(struct interface *ifp, unsigned interval)
debugf("Sending hello %d (%d) to %s.\n",
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, ifp->hello_seqno);
accumulate_short(ifp, interval > 0xFFFF ? 0xFFFF : interval);
end_message(ifp, MESSAGE_HELLO, 6);
ifp->have_buffered_hello = 1;
if(ifp->enable_timestamps) {
/* 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
......@@ -764,6 +951,7 @@ flush_unicast(int dofree)
sin6.sin6_port = htons(protocol_port);
sin6.sin6_scope_id = unicast_neighbour->ifp->ifindex;
DO_HTONS(packet_header + 2, unicast_buffered);
fill_rtt_message(unicast_neighbour->ifp);
rc = babel_send(protocol_socket,
packet_header, sizeof(packet_header),
unicast_buffer, unicast_buffered,
......@@ -1206,6 +1394,8 @@ send_ihu(struct neighbour *neigh, struct interface *ifp)
{
int rxcost, interval;
int ll;
int send_rtt_data;
int msglen;
if(neigh == NULL && ifp == NULL) {
struct interface *ifp_aux;
......@@ -1249,8 +1439,21 @@ send_ihu(struct neighbour *neigh, struct interface *ifp)
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) {
start_message(ifp, MESSAGE_IHU, ll ? 14 : 22);
start_message(ifp, MESSAGE_IHU, msglen);
accumulate_byte(ifp, ll ? 3 : 2);
accumulate_byte(ifp, 0);
accumulate_short(ifp, rxcost);
......@@ -1259,10 +1462,16 @@ send_ihu(struct neighbour *neigh, struct interface *ifp)
accumulate_bytes(ifp, neigh->address + 8, 8);
else
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 {
int rc;
rc = start_unicast_message(neigh, MESSAGE_IHU, ll ? 14 : 22);
rc = start_unicast_message(neigh, MESSAGE_IHU, msglen);
if(rc < 0) return;
accumulate_unicast_byte(neigh, ll ? 3 : 2);
accumulate_unicast_byte(neigh, 0);
......@@ -1272,7 +1481,14 @@ send_ihu(struct neighbour *neigh, struct interface *ifp)
accumulate_unicast_bytes(neigh, neigh->address + 8, 8);
else
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.
#define SUBTLV_PAD1 0
#define SUBTLV_PADN 1
#define SUBTLV_DIVERSITY 2 /* Also known as babelz. */
#define SUBTLV_TIMESTAMP 3 /* Used to compute RTT. */
extern unsigned short myseqno;
extern struct timeval seqno_time;
......
......@@ -25,6 +25,7 @@ THE SOFTWARE.
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <assert.h>
#include "babeld.h"
#include "util.h"
......@@ -97,6 +98,10 @@ find_neighbour(const unsigned char *address, struct interface *ifp)
neigh->hello_time = zero;
neigh->hello_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->next = neighs;
neighs = 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
neighbour_cost(struct neighbour *neigh)
{
unsigned a, b;
unsigned a, b, cost;
if(!if_up(neigh->ifp))
return INFINITY;
......@@ -311,7 +339,7 @@ neighbour_cost(struct neighbour *neigh)
return INFINITY;
if(!(neigh->ifp->flags & IF_LQ) || (a < 256 && b < 256)) {
return a;
cost = a;
} else {
/* a = 256/alpha, b = 256/beta, where alpha and beta are the expected
probabilities of a packet getting through in the direct and reverse
......@@ -320,6 +348,16 @@ neighbour_cost(struct neighbour *neigh)
b = MAX(b, 256);
/* 1/(alpha * beta), which is just plain ETX. */
/* 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 {
struct timeval ihu_time;
unsigned short hello_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;
};
......@@ -47,4 +54,6 @@ int update_neighbour(struct neighbour *neigh, int hello, int hello_interval);
unsigned check_neighbours(void);
unsigned neighbour_txcost(struct neighbour *neigh);
unsigned neighbour_rxcost(struct neighbour *neigh);
unsigned neighbour_rttcost(struct neighbour *neigh);
unsigned neighbour_cost(struct neighbour *neigh);
int valid_rtt(struct neighbour *neigh);
......@@ -152,8 +152,10 @@ parse_nat(const char *string)
return (int)l;
}
/* Given a fixed-point string such as "42.1337", returns 1000 times
the value of the string, here 42133. */
int
parse_msec(const char *string)
parse_thousands(const char *string)
{
unsigned int in, fl;
int i, j;
......@@ -293,6 +295,16 @@ format_eui64(const unsigned char *eui)
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
parse_address(const char *address, unsigned char *addr_r, int *af_r)
{
......
......@@ -66,6 +66,14 @@ seqno_plus(unsigned short s, int plus)
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);
void timeval_minus(struct timeval *d,
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_sec(struct timeval *d, time_t secs);
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, ...)
ATTRIBUTE ((format (printf, 2, 3))) COLD;
int in_prefix(const unsigned char *restrict address,
......@@ -90,6 +98,7 @@ unsigned char *mask_prefix(unsigned char *restrict ret,
const char *format_address(const unsigned char *address);
const char *format_prefix(const unsigned char *address, unsigned char prefix);
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_net(const char *net, unsigned char *prefix_r, unsigned char *plen_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