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)
......
This diff is collapsed.
......@@ -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