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