Compare commits
5 commits
Author | SHA1 | Date | |
---|---|---|---|
6269f404fc | |||
|
d9763bd7a0 | ||
|
94ebf8e00e | ||
|
071354da5b | ||
|
8657e7e703 |
7 changed files with 502 additions and 34 deletions
|
@ -1907,8 +1907,9 @@ protocol babel [<name>] {
|
||||||
ipv4 { <channel config> };
|
ipv4 { <channel config> };
|
||||||
ipv6 [sadr] { <channel config> };
|
ipv6 [sadr] { <channel config> };
|
||||||
randomize router id <switch>;
|
randomize router id <switch>;
|
||||||
|
metric decay <time>;
|
||||||
interface <interface pattern> {
|
interface <interface pattern> {
|
||||||
type <wired|wireless>;
|
type <wired|wireless|tunnel>;
|
||||||
rxcost <number>;
|
rxcost <number>;
|
||||||
limit <number>;
|
limit <number>;
|
||||||
hello interval <time>;
|
hello interval <time>;
|
||||||
|
@ -1921,6 +1922,11 @@ protocol babel [<name>] {
|
||||||
check link <switch>;
|
check link <switch>;
|
||||||
next hop ipv4 <address>;
|
next hop ipv4 <address>;
|
||||||
next hop ipv6 <address>;
|
next hop ipv6 <address>;
|
||||||
|
rtt cost <number>;
|
||||||
|
rtt min <time>;
|
||||||
|
rtt max <time>;
|
||||||
|
rtt winlen <number>;
|
||||||
|
send timestamps <switch>;
|
||||||
authentication none|mac [permissive];
|
authentication none|mac [permissive];
|
||||||
password "<text>";
|
password "<text>";
|
||||||
password "<text>" {
|
password "<text>" {
|
||||||
|
@ -1951,15 +1957,27 @@ protocol babel [<name>] {
|
||||||
router ID every time it starts up, which avoids this problem at the cost
|
router ID every time it starts up, which avoids this problem at the cost
|
||||||
of not having stable router IDs in the network. Default: no.
|
of not having stable router IDs in the network. Default: no.
|
||||||
|
|
||||||
<tag><label id="babel-type">type wired|wireless </tag>
|
<tag><label id="babel-metric-decay">metric decay <m/time/ s</tag>
|
||||||
This option specifies the interface type: Wired or wireless. On wired
|
The metric smoothing decay time. When route metrics vary (because of
|
||||||
interfaces a neighbor is considered unreachable after a small number of
|
varying quality of a wireless link, or varying RTT when timestamps are
|
||||||
Hello packets are lost, as described by <cf/limit/ option. On wireless
|
enabled), Babel applies an exponential smoothing procedure to the metric
|
||||||
|
to dampen route oscillations. This parameter specifies the half-life of
|
||||||
|
the convergence of the smoothed metric to the actual metric of the route.
|
||||||
|
I.e., the distance between the smoothed and the actual metric will be
|
||||||
|
halfed for each time period specified here (until they converge). Set to 0
|
||||||
|
to disable metric smoothing; if set, the value must be in the interval
|
||||||
|
1-180 s. Default: 4 s
|
||||||
|
|
||||||
|
<tag><label id="babel-type">type wired|wireless|tunnel </tag>
|
||||||
|
This option specifies the interface type: Wired, wireless or tunnel. On
|
||||||
|
wired interfaces a neighbor is considered unreachable after a small number
|
||||||
|
of Hello packets are lost, as described by <cf/limit/ option. On wireless
|
||||||
interfaces the ETX link quality estimation technique is used to compute
|
interfaces the ETX link quality estimation technique is used to compute
|
||||||
the metrics of routes discovered over this interface. This technique will
|
the metrics of routes discovered over this interface. This technique will
|
||||||
gradually degrade the metric of routes when packets are lost rather than
|
gradually degrade the metric of routes when packets are lost rather than
|
||||||
the more binary up/down mechanism of wired type links. Default:
|
the more binary up/down mechanism of wired type links. A tunnel is like a
|
||||||
<cf/wired/.
|
wired interface, but turns on RTT-based metrics with a default cost of 96.
|
||||||
|
Default: <cf/wired/.
|
||||||
|
|
||||||
<tag><label id="babel-rxcost">rxcost <m/num/</tag>
|
<tag><label id="babel-rxcost">rxcost <m/num/</tag>
|
||||||
This option specifies the nominal RX cost of the interface. The effective
|
This option specifies the nominal RX cost of the interface. The effective
|
||||||
|
@ -2025,6 +2043,37 @@ protocol babel [<name>] {
|
||||||
source for Babel packets will be used. In normal operation, it should not
|
source for Babel packets will be used. In normal operation, it should not
|
||||||
be necessary to set this option.
|
be necessary to set this option.
|
||||||
|
|
||||||
|
<tag><label id="babel-rtt-cost">rtt cost <m/number/</tag>
|
||||||
|
The RTT-based cost that will be applied to all routes from each neighbour
|
||||||
|
based on the measured RTT to that neighbour. If this value is set,
|
||||||
|
timestamps will be included in generated Babel Hello and IHU messages, and
|
||||||
|
(if the neighbours also have timestamps enabled), the RTT to each
|
||||||
|
neighbour will be computed. An additional cost is added to a neighbour if
|
||||||
|
its RTT is above the <ref id="babel-rtt-min" name="rtt min"> value
|
||||||
|
configured on the interface. The added cost scales linearly from 0 up to
|
||||||
|
the RTT cost configured in this option; the full cost is applied if the
|
||||||
|
neighbour RTT reaches the RTT configured in the <ref id="babel-rtt-max"
|
||||||
|
name="rtt max"> option (and for all RTTs above this value). Default: 0
|
||||||
|
(disabled), except for tunnel interfaces, where it is 96.
|
||||||
|
|
||||||
|
<tag><label id="babel-rtt-min">rtt min <m/time/ s|ms</tag>
|
||||||
|
The minimum RTT above which the RTT cost will start to be applied (scaling
|
||||||
|
linearly from zero up to the full cost). Default: 10 ms
|
||||||
|
|
||||||
|
<tag><label id="babel-rtt-max">rtt max <m/time/ s|ms</tag>
|
||||||
|
The maximum RTT above which the full RTT cost will start be applied.
|
||||||
|
Default: 120 ms
|
||||||
|
|
||||||
|
<tag><label id="babel-rtt-winlen">rtt winlen <m/number/</tag>
|
||||||
|
The window length user to calculate median of the RTT
|
||||||
|
samples from each neighbour, Lower values discards old
|
||||||
|
RTT samples faster. Must be between 1 and 65535. Default: 100
|
||||||
|
|
||||||
|
<tag><label id="babel-send-timestamps">send timestamps <m/switch/</tag>
|
||||||
|
Whether to send the timestamps used for RTT calculation on this interface.
|
||||||
|
Sending the timestamps enables peers to calculate an RTT to this node,
|
||||||
|
even if no RTT cost is applied to the route metrics. Default: yes.
|
||||||
|
|
||||||
<tag><label id="babel-authentication">authentication none|mac [permissive]</tag>
|
<tag><label id="babel-authentication">authentication none|mac [permissive]</tag>
|
||||||
Selects authentication method to be used. <cf/none/ means that packets
|
Selects authentication method to be used. <cf/none/ means that packets
|
||||||
are not authenticated at all, <cf/mac/ means MAC authentication is
|
are not authenticated at all, <cf/mac/ means MAC authentication is
|
||||||
|
|
13
lib/timer.c
13
lib/timer.c
|
@ -76,6 +76,19 @@ current_time(void)
|
||||||
return timeloop_current()->last_time;
|
return timeloop_current()->last_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
btime
|
||||||
|
current_time_now(void)
|
||||||
|
{
|
||||||
|
struct timespec ts;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
rv = clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||||
|
if (rv < 0)
|
||||||
|
die("clock_gettime: %m");
|
||||||
|
|
||||||
|
return ts.tv_sec S + ts.tv_nsec NS;
|
||||||
|
}
|
||||||
|
|
||||||
btime
|
btime
|
||||||
current_real_time(void)
|
current_real_time(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -44,6 +44,7 @@ static inline timer *timers_first(struct timeloop *loop)
|
||||||
extern struct timeloop main_timeloop;
|
extern struct timeloop main_timeloop;
|
||||||
|
|
||||||
btime current_time(void);
|
btime current_time(void);
|
||||||
|
btime current_time_now(void);
|
||||||
btime current_real_time(void);
|
btime current_real_time(void);
|
||||||
|
|
||||||
//#define now (current_time() TO_S)
|
//#define now (current_time() TO_S)
|
||||||
|
|
|
@ -134,6 +134,103 @@ babel_expire_sources(struct babel_proto *p UNUSED, struct babel_entry *e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u16
|
||||||
|
babel_calc_smoothed_metric(struct babel_proto *p, struct babel_route *r, u8 update)
|
||||||
|
{
|
||||||
|
struct babel_config *cf = (void *) p->p.cf;
|
||||||
|
uint metric = r->metric, smoothed_metric = r->smoothed_metric;
|
||||||
|
btime smoothed_time = r->smoothed_time, now = current_time();
|
||||||
|
|
||||||
|
if (!cf->metric_decay || metric == BABEL_INFINITY ||
|
||||||
|
metric == smoothed_metric || !smoothed_time)
|
||||||
|
{
|
||||||
|
smoothed_metric = metric;
|
||||||
|
smoothed_time = now;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
int diff = metric - smoothed_metric;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The decay defines the half-life of the metric convergence, so first iterate
|
||||||
|
* in halving steps
|
||||||
|
*/
|
||||||
|
while (smoothed_time < now - cf->metric_decay && diff) {
|
||||||
|
smoothed_metric += diff/2;
|
||||||
|
smoothed_time += cf->metric_decay;
|
||||||
|
diff = metric - smoothed_metric;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Then, update remainder in BABEL_SMOOTHING_STEP intervals using the
|
||||||
|
* exponential function (approximated via the pre-computed reciprocal).
|
||||||
|
*/
|
||||||
|
while (smoothed_time < now - BABEL_SMOOTHING_STEP && diff) {
|
||||||
|
smoothed_metric += (BABEL_SMOOTHING_STEP * diff *
|
||||||
|
(cf->smooth_recp - BABEL_SMOOTHING_UNIT) / BABEL_SMOOTHING_UNIT);
|
||||||
|
smoothed_time += BABEL_SMOOTHING_STEP;
|
||||||
|
diff = metric - smoothed_metric;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Consider the metric converged once we're close enough */
|
||||||
|
if (ABS(diff) < BABEL_SMOOTHING_MIN_DIFF)
|
||||||
|
smoothed_metric = metric;
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (update) {
|
||||||
|
r->smoothed_metric = smoothed_metric;
|
||||||
|
r->smoothed_time = smoothed_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
return smoothed_metric;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u16
|
||||||
|
babel_update_smoothed_metric(struct babel_proto *p, struct babel_route *r)
|
||||||
|
{
|
||||||
|
if (!r->metric)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!r->smoothed_metric) {
|
||||||
|
r->smoothed_metric = r->metric;
|
||||||
|
r->smoothed_time = current_time();
|
||||||
|
return r->smoothed_metric;
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 smoothed = babel_calc_smoothed_metric(p, r, 1);
|
||||||
|
DBG("Updated smoothed metric for prefix %N: router-id %lR metric %d/%d\n",
|
||||||
|
r->e->n.addr, r->router_id, r->metric, smoothed);
|
||||||
|
|
||||||
|
return smoothed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u16
|
||||||
|
babel_smoothed_metric(struct babel_proto *p, struct babel_route *r)
|
||||||
|
{
|
||||||
|
return babel_calc_smoothed_metric(p, r, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
babel_update_metric(struct babel_proto *p, struct babel_route *r, u16 metric)
|
||||||
|
{
|
||||||
|
babel_update_smoothed_metric(p, r);
|
||||||
|
r->metric = metric;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u8
|
||||||
|
babel_route_better(struct babel_proto *p, struct babel_route *mod,
|
||||||
|
struct babel_route *best)
|
||||||
|
{
|
||||||
|
if (!mod->feasible)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!best)
|
||||||
|
return mod->metric < BABEL_INFINITY;
|
||||||
|
|
||||||
|
return (mod->metric < best->metric &&
|
||||||
|
babel_smoothed_metric(p, mod) < babel_smoothed_metric(p, best));
|
||||||
|
}
|
||||||
|
|
||||||
static struct babel_route *
|
static struct babel_route *
|
||||||
babel_find_route(struct babel_entry *e, struct babel_neighbor *n)
|
babel_find_route(struct babel_entry *e, struct babel_neighbor *n)
|
||||||
{
|
{
|
||||||
|
@ -151,8 +248,10 @@ babel_get_route(struct babel_proto *p, struct babel_entry *e, struct babel_neigh
|
||||||
{
|
{
|
||||||
struct babel_route *r = babel_find_route(e, nbr);
|
struct babel_route *r = babel_find_route(e, nbr);
|
||||||
|
|
||||||
if (r)
|
if (r) {
|
||||||
|
babel_update_smoothed_metric(p, r);
|
||||||
return r;
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
r = sl_allocz(p->route_slab);
|
r = sl_allocz(p->route_slab);
|
||||||
|
|
||||||
|
@ -304,7 +403,7 @@ babel_add_seqno_request(struct babel_proto *p, struct babel_entry *e,
|
||||||
struct babel_seqno_request *sr;
|
struct babel_seqno_request *sr;
|
||||||
|
|
||||||
WALK_LIST(sr, e->requests)
|
WALK_LIST(sr, e->requests)
|
||||||
if (sr->router_id == router_id)
|
if (sr->router_id == router_id && sr->nbr == nbr)
|
||||||
{
|
{
|
||||||
/* Found matching or newer */
|
/* Found matching or newer */
|
||||||
if (ge_mod64k(sr->seqno, seqno) && seqno_request_valid(sr))
|
if (ge_mod64k(sr->seqno, seqno) && seqno_request_valid(sr))
|
||||||
|
@ -351,17 +450,20 @@ static int
|
||||||
babel_satisfy_seqno_request(struct babel_proto *p, struct babel_entry *e,
|
babel_satisfy_seqno_request(struct babel_proto *p, struct babel_entry *e,
|
||||||
u64 router_id, u16 seqno)
|
u64 router_id, u16 seqno)
|
||||||
{
|
{
|
||||||
struct babel_seqno_request *sr;
|
struct babel_seqno_request *sr, *srx;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
WALK_LIST(sr, e->requests)
|
WALK_LIST_DELSAFE(sr, srx, e->requests)
|
||||||
if ((sr->router_id == router_id) && ge_mod64k(seqno, sr->seqno))
|
if ((sr->router_id == router_id) && ge_mod64k(seqno, sr->seqno))
|
||||||
{
|
{
|
||||||
/* Found the request, remove it */
|
/* Found a matching request, remove it; there may be multiple outstanding
|
||||||
|
* requests, so continue looping
|
||||||
|
*/
|
||||||
babel_remove_seqno_request(p, sr);
|
babel_remove_seqno_request(p, sr);
|
||||||
return 1;
|
ret = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -434,6 +536,10 @@ babel_get_neighbor(struct babel_iface *ifa, ip_addr addr)
|
||||||
init_list(&nbr->requests);
|
init_list(&nbr->requests);
|
||||||
add_tail(&ifa->neigh_list, NODE nbr);
|
add_tail(&ifa->neigh_list, NODE nbr);
|
||||||
|
|
||||||
|
nbr->srtt_pool = mb_allocz(ifa->pool, ifa->cf->rtt_win_len*sizeof(btime));
|
||||||
|
nbr->srtt_pool_sorted = mb_allocz(ifa->pool, ifa->cf->rtt_win_len*sizeof(btime));
|
||||||
|
nbr->srtt_poll_idx = nbr->srtt_pool_len = 0;
|
||||||
|
|
||||||
return nbr;
|
return nbr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -458,6 +564,8 @@ babel_flush_neighbor(struct babel_proto *p, struct babel_neighbor *nbr)
|
||||||
|
|
||||||
nbr->ifa = NULL;
|
nbr->ifa = NULL;
|
||||||
rem_node(NODE nbr);
|
rem_node(NODE nbr);
|
||||||
|
mb_free(nbr->srtt_pool);
|
||||||
|
mb_free(nbr->srtt_pool_sorted);
|
||||||
mb_free(nbr);
|
mb_free(nbr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -569,6 +677,7 @@ babel_update_cost(struct babel_neighbor *nbr)
|
||||||
switch (cf->type)
|
switch (cf->type)
|
||||||
{
|
{
|
||||||
case BABEL_IFACE_TYPE_WIRED:
|
case BABEL_IFACE_TYPE_WIRED:
|
||||||
|
case BABEL_IFACE_TYPE_TUNNEL:
|
||||||
/* k-out-of-j selection - Appendix 2.1 in the RFC. */
|
/* k-out-of-j selection - Appendix 2.1 in the RFC. */
|
||||||
|
|
||||||
/* Link is bad if less than cf->limit/16 of expected hellos were received */
|
/* Link is bad if less than cf->limit/16 of expected hellos were received */
|
||||||
|
@ -597,6 +706,25 @@ babel_update_cost(struct babel_neighbor *nbr)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cf->rtt_cost && nbr->srtt > cf->rtt_min)
|
||||||
|
{
|
||||||
|
uint rtt_cost = cf->rtt_cost;
|
||||||
|
|
||||||
|
if (nbr->srtt < cf->rtt_max)
|
||||||
|
{
|
||||||
|
uint rtt_interval = cf->rtt_max TO_US - cf->rtt_min TO_US;
|
||||||
|
uint rtt_diff = (nbr->srtt TO_US - cf->rtt_min TO_US);
|
||||||
|
|
||||||
|
rtt_cost = (rtt_cost * rtt_diff) / rtt_interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
txcost = MIN(txcost + rtt_cost, BABEL_INFINITY);
|
||||||
|
rxcost = MIN(rxcost + rtt_cost, BABEL_INFINITY);
|
||||||
|
|
||||||
|
TRACE(D_EVENTS, "Added RTT cost %u to nbr %I on %s with srtt %u.%03u ms",
|
||||||
|
rtt_cost, nbr->addr, nbr->ifa->iface->name, nbr->srtt/1000, nbr->srtt%1000);
|
||||||
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
/* If RX cost changed, send IHU with next Hello */
|
/* If RX cost changed, send IHU with next Hello */
|
||||||
if (rxcost != nbr->rxcost)
|
if (rxcost != nbr->rxcost)
|
||||||
|
@ -616,7 +744,7 @@ done:
|
||||||
struct babel_route *r; node *n;
|
struct babel_route *r; node *n;
|
||||||
WALK_LIST2(r, n, nbr->routes, neigh_route)
|
WALK_LIST2(r, n, nbr->routes, neigh_route)
|
||||||
{
|
{
|
||||||
r->metric = babel_compute_metric(nbr, r->advert_metric);
|
babel_update_metric(p, r, babel_compute_metric(nbr, r->advert_metric));
|
||||||
babel_select_route(p, r->e, r);
|
babel_select_route(p, r->e, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -757,8 +885,7 @@ babel_select_route(struct babel_proto *p, struct babel_entry *e, struct babel_ro
|
||||||
/* Shortcut if only non-best was modified */
|
/* Shortcut if only non-best was modified */
|
||||||
if (mod && (mod != best))
|
if (mod && (mod != best))
|
||||||
{
|
{
|
||||||
/* Either select modified route, or keep old best route */
|
if (babel_route_better(p, mod, best))
|
||||||
if ((mod->metric < (best ? best->metric : BABEL_INFINITY)) && mod->feasible)
|
|
||||||
best = mod;
|
best = mod;
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
@ -769,17 +896,24 @@ babel_select_route(struct babel_proto *p, struct babel_entry *e, struct babel_ro
|
||||||
if (!best || (best->metric == BABEL_INFINITY) || !best->feasible)
|
if (!best || (best->metric == BABEL_INFINITY) || !best->feasible)
|
||||||
best = NULL;
|
best = NULL;
|
||||||
|
|
||||||
|
/* best will be compared to many routes below, make sure it's up-to-date */
|
||||||
|
if (best)
|
||||||
|
babel_update_smoothed_metric(p, best);
|
||||||
|
|
||||||
/* Find the best feasible route from all routes */
|
/* Find the best feasible route from all routes */
|
||||||
WALK_LIST(r, e->routes)
|
WALK_LIST(r, e->routes)
|
||||||
if ((r->metric < (best ? best->metric : BABEL_INFINITY)) && r->feasible)
|
if (babel_route_better(p, r, best))
|
||||||
best = r;
|
best = r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (best)
|
if (best)
|
||||||
{
|
{
|
||||||
if (best != e->selected)
|
if (best != e->selected)
|
||||||
TRACE(D_EVENTS, "Picked new route for prefix %N: router-id %lR metric %d",
|
{
|
||||||
e->n.addr, best->router_id, best->metric);
|
u16 smoothed = babel_update_smoothed_metric(p, best);
|
||||||
|
TRACE(D_EVENTS, "Picked new route for prefix %N: router-id %lR metric %d/%d",
|
||||||
|
e->n.addr, best->router_id, best->metric, smoothed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (e->selected)
|
else if (e->selected)
|
||||||
{
|
{
|
||||||
|
@ -828,6 +962,12 @@ babel_build_ihu(union babel_msg *msg, struct babel_iface *ifa, struct babel_neig
|
||||||
msg->ihu.rxcost = n->rxcost;
|
msg->ihu.rxcost = n->rxcost;
|
||||||
msg->ihu.interval = ifa->cf->ihu_interval;
|
msg->ihu.interval = ifa->cf->ihu_interval;
|
||||||
|
|
||||||
|
if (n->last_tstamp_rcvd && ifa->cf->rtt_send)
|
||||||
|
{
|
||||||
|
msg->ihu.tstamp = n->last_tstamp;
|
||||||
|
msg->ihu.tstamp_rcvd = n->last_tstamp_rcvd TO_US;
|
||||||
|
}
|
||||||
|
|
||||||
TRACE(D_PACKETS, "Sending IHU for %I with rxcost %d interval %t",
|
TRACE(D_PACKETS, "Sending IHU for %I with rxcost %d interval %t",
|
||||||
msg->ihu.addr, msg->ihu.rxcost, (btime) msg->ihu.interval);
|
msg->ihu.addr, msg->ihu.rxcost, (btime) msg->ihu.interval);
|
||||||
}
|
}
|
||||||
|
@ -867,6 +1007,9 @@ babel_send_hello(struct babel_iface *ifa, uint interval)
|
||||||
msg.hello.seqno = ifa->hello_seqno++;
|
msg.hello.seqno = ifa->hello_seqno++;
|
||||||
msg.hello.interval = interval ?: ifa->cf->hello_interval;
|
msg.hello.interval = interval ?: ifa->cf->hello_interval;
|
||||||
|
|
||||||
|
if (ifa->cf->rtt_send)
|
||||||
|
msg.hello.tstamp = 1; /* real timestamp will be set on TLV write */
|
||||||
|
|
||||||
TRACE(D_PACKETS, "Sending hello on %s with seqno %d interval %t",
|
TRACE(D_PACKETS, "Sending hello on %s with seqno %d interval %t",
|
||||||
ifa->ifname, msg.hello.seqno, (btime) msg.hello.interval);
|
ifa->ifname, msg.hello.seqno, (btime) msg.hello.interval);
|
||||||
|
|
||||||
|
@ -1162,14 +1305,41 @@ babel_handle_hello(union babel_msg *m, struct babel_iface *ifa)
|
||||||
msg->seqno, (btime) msg->interval);
|
msg->seqno, (btime) msg->interval);
|
||||||
|
|
||||||
struct babel_neighbor *n = babel_get_neighbor(ifa, msg->sender);
|
struct babel_neighbor *n = babel_get_neighbor(ifa, msg->sender);
|
||||||
|
struct babel_iface_config *cf = n->ifa->cf;
|
||||||
int first_hello = !n->hello_cnt;
|
int first_hello = !n->hello_cnt;
|
||||||
|
|
||||||
|
if (msg->tstamp)
|
||||||
|
{
|
||||||
|
n->last_tstamp = msg->tstamp;
|
||||||
|
n->last_tstamp_rcvd = msg->pkt_received;
|
||||||
|
}
|
||||||
babel_update_hello_history(n, msg->seqno, msg->interval);
|
babel_update_hello_history(n, msg->seqno, msg->interval);
|
||||||
babel_update_cost(n);
|
babel_update_cost(n);
|
||||||
|
|
||||||
/* Speed up session establishment by sending IHU immediately */
|
/* Speed up session establishment by sending IHU immediately */
|
||||||
if (first_hello)
|
if (first_hello)
|
||||||
babel_send_ihu(ifa, n);
|
{
|
||||||
|
/* if using RTT, all IHUs must be paired with hellos */
|
||||||
|
if(cf->rtt_send)
|
||||||
|
babel_send_hello(ifa, 0);
|
||||||
|
else
|
||||||
|
babel_send_ihu(ifa, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
babel_btime_cmp(const void *b1, const void *b2)
|
||||||
|
{
|
||||||
|
btime r;
|
||||||
|
switch (r = *(btime*)b1 - *(btime*)b2)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return r > (btime)0 ? 1 : -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1188,6 +1358,51 @@ babel_handle_ihu(union babel_msg *m, struct babel_iface *ifa)
|
||||||
struct babel_neighbor *n = babel_get_neighbor(ifa, msg->sender);
|
struct babel_neighbor *n = babel_get_neighbor(ifa, msg->sender);
|
||||||
n->txcost = msg->rxcost;
|
n->txcost = msg->rxcost;
|
||||||
n->ihu_expiry = current_time() + BABEL_IHU_EXPIRY_FACTOR(msg->interval);
|
n->ihu_expiry = current_time() + BABEL_IHU_EXPIRY_FACTOR(msg->interval);
|
||||||
|
|
||||||
|
if (msg->tstamp)
|
||||||
|
{
|
||||||
|
u32 rtt_sample = 0, pkt_received = msg->pkt_received TO_US;
|
||||||
|
int remote_time, full_time;
|
||||||
|
|
||||||
|
/* processing time reported by peer */
|
||||||
|
remote_time = (n->last_tstamp - msg->tstamp_rcvd);
|
||||||
|
/* time since we sent the last timestamp - RTT including remote time */
|
||||||
|
full_time = (pkt_received - msg->tstamp);
|
||||||
|
|
||||||
|
/* sanity checks */
|
||||||
|
if (remote_time < 0 || full_time < 0 ||
|
||||||
|
remote_time US_ > BABEL_RTT_MAX_VALUE || full_time US_ > BABEL_RTT_MAX_VALUE)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (remote_time < full_time)
|
||||||
|
rtt_sample = full_time - remote_time;
|
||||||
|
|
||||||
|
if (n->srtt)
|
||||||
|
{
|
||||||
|
u16 pool_idx = n->srtt_poll_idx % n->ifa->cf->rtt_win_len;
|
||||||
|
n->srtt_poll_idx = pool_idx + 1;
|
||||||
|
*(n->srtt_pool + pool_idx) = rtt_sample;
|
||||||
|
if (n->srtt_pool_len < n->ifa->cf->rtt_win_len)
|
||||||
|
n->srtt_pool_len++;
|
||||||
|
memcpy(n->srtt_pool_sorted, n->srtt_pool, (size_t)n->srtt_pool_len*sizeof(btime));
|
||||||
|
// use qsort for now for testing
|
||||||
|
qsort(n->srtt_pool_sorted, (size_t)n->srtt_pool_len, sizeof(btime), babel_btime_cmp);
|
||||||
|
int mid = n->srtt_pool_len / (u16)2;
|
||||||
|
if (!n->srtt_pool_len || n->srtt_pool_len % (u16)2)
|
||||||
|
n->srtt = *(n->srtt_pool_sorted + mid);
|
||||||
|
else
|
||||||
|
n->srtt = (*(n->srtt_pool_sorted + mid - (u16)1) + *(n->srtt_pool_sorted + mid)) / (u16)2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*(n->srtt_pool) = n->srtt = rtt_sample;
|
||||||
|
n->srtt_poll_idx = n->srtt_pool_len = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE(D_EVENTS, "RTT sample for neighbour %I on %s: %u us (srtt %u.%03u ms)",
|
||||||
|
n->addr, ifa->ifname, rtt_sample, n->srtt/1000, n->srtt%1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
babel_update_cost(n);
|
babel_update_cost(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1304,9 +1519,9 @@ babel_handle_update(union babel_msg *m, struct babel_iface *ifa)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Last paragraph above - update the entry */
|
/* Last paragraph above - update the entry */
|
||||||
|
babel_update_metric(p, r, metric);
|
||||||
r->feasible = feasible;
|
r->feasible = feasible;
|
||||||
r->seqno = msg->seqno;
|
r->seqno = msg->seqno;
|
||||||
r->metric = metric;
|
|
||||||
r->advert_metric = msg->metric;
|
r->advert_metric = msg->metric;
|
||||||
r->router_id = msg->router_id;
|
r->router_id = msg->router_id;
|
||||||
r->next_hop = msg->next_hop;
|
r->next_hop = msg->next_hop;
|
||||||
|
@ -2112,8 +2327,8 @@ babel_show_neighbors(struct proto *P, const char *iff)
|
||||||
}
|
}
|
||||||
|
|
||||||
cli_msg(-1024, "%s:", p->p.name);
|
cli_msg(-1024, "%s:", p->p.name);
|
||||||
cli_msg(-1024, "%-25s %-10s %6s %6s %6s %7s %4s",
|
cli_msg(-1024, "%-25s %-10s %6s %6s %6s %7s %4s %11s",
|
||||||
"IP address", "Interface", "Metric", "Routes", "Hellos", "Expires", "Auth");
|
"IP address", "Interface", "Metric", "Routes", "Hellos", "Expires", "Auth", "RTT");
|
||||||
|
|
||||||
WALK_LIST(ifa, p->interfaces)
|
WALK_LIST(ifa, p->interfaces)
|
||||||
{
|
{
|
||||||
|
@ -2128,9 +2343,10 @@ babel_show_neighbors(struct proto *P, const char *iff)
|
||||||
|
|
||||||
uint hellos = u32_popcount(n->hello_map);
|
uint hellos = u32_popcount(n->hello_map);
|
||||||
btime timer = (n->hello_expiry ?: n->init_expiry) - current_time();
|
btime timer = (n->hello_expiry ?: n->init_expiry) - current_time();
|
||||||
cli_msg(-1024, "%-25I %-10s %6u %6u %6u %7t %-4s",
|
cli_msg(-1024, "%-25I %-10s %6u %6u %6u %7t %-4s %5u.%03ums",
|
||||||
n->addr, ifa->iface->name, n->cost, rts, hellos, MAX(timer, 0),
|
n->addr, ifa->iface->name, n->cost, rts, hellos, MAX(timer, 0),
|
||||||
n->auth_passed ? "Yes" : "No");
|
n->auth_passed ? "Yes" : "No",
|
||||||
|
n->srtt/1000, n->srtt%1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,10 +51,28 @@
|
||||||
#define BABEL_GARBAGE_INTERVAL (300 S_)
|
#define BABEL_GARBAGE_INTERVAL (300 S_)
|
||||||
#define BABEL_RXCOST_WIRED 96
|
#define BABEL_RXCOST_WIRED 96
|
||||||
#define BABEL_RXCOST_WIRELESS 256
|
#define BABEL_RXCOST_WIRELESS 256
|
||||||
|
#define BABEL_RXCOST_RTT 96
|
||||||
#define BABEL_INITIAL_HOP_COUNT 255
|
#define BABEL_INITIAL_HOP_COUNT 255
|
||||||
#define BABEL_MAX_SEND_INTERVAL 5 /* Unused ? */
|
#define BABEL_MAX_SEND_INTERVAL 5 /* Unused ? */
|
||||||
#define BABEL_INITIAL_NEIGHBOR_TIMEOUT (60 S_)
|
#define BABEL_INITIAL_NEIGHBOR_TIMEOUT (60 S_)
|
||||||
|
|
||||||
|
#define BABEL_RTT_MAX_VALUE (600 S_)
|
||||||
|
#define BABEL_RTT_MIN (10 MS_)
|
||||||
|
#define BABEL_RTT_MAX (120 MS_)
|
||||||
|
#define BABEL_RTT_WINLEN 100
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Constants for calculating metric smoothing. Chosen so that:
|
||||||
|
* log(2) = BABEL_SMOOTHING_CONSTANT / BABEL_SMOOTHING_UNIT, which means that
|
||||||
|
* log(2)/x can be calculated as BABEL_SMOOTHING_UNIT + BABEL_SMOOTHING_CONSTANT / x
|
||||||
|
*/
|
||||||
|
#define BABEL_SMOOTHING_UNIT 0x10000000
|
||||||
|
#define BABEL_SMOOTHING_CONSTANT 186065279
|
||||||
|
#define BABEL_SMOOTHING_STEP (1 S_) /* smoothing calculated in this step size */
|
||||||
|
#define BABEL_SMOOTHING_MIN_DIFF 4 /* metric diff beneath this is converged */
|
||||||
|
#define BABEL_SMOOTHING_DECAY (4 S_)
|
||||||
|
#define BABEL_SMOOTHING_DECAY_MAX (180 S_)
|
||||||
|
|
||||||
/* Max interval that will not overflow when carried as 16-bit centiseconds */
|
/* Max interval that will not overflow when carried as 16-bit centiseconds */
|
||||||
#define BABEL_TIME_UNITS 10000 /* On-wire times are counted in centiseconds */
|
#define BABEL_TIME_UNITS 10000 /* On-wire times are counted in centiseconds */
|
||||||
#define BABEL_MIN_INTERVAL (0x0001 * BABEL_TIME_UNITS)
|
#define BABEL_MIN_INTERVAL (0x0001 * BABEL_TIME_UNITS)
|
||||||
|
@ -94,6 +112,8 @@ enum babel_tlv_type {
|
||||||
enum babel_subtlv_type {
|
enum babel_subtlv_type {
|
||||||
BABEL_SUBTLV_PAD1 = 0,
|
BABEL_SUBTLV_PAD1 = 0,
|
||||||
BABEL_SUBTLV_PADN = 1,
|
BABEL_SUBTLV_PADN = 1,
|
||||||
|
BABEL_SUBTLV_DIVERSITY = 2, /* we don't support this */
|
||||||
|
BABEL_SUBTLV_TIMESTAMP = 3,
|
||||||
|
|
||||||
/* Mandatory subtlvs */
|
/* Mandatory subtlvs */
|
||||||
BABEL_SUBTLV_SOURCE_PREFIX = 128,
|
BABEL_SUBTLV_SOURCE_PREFIX = 128,
|
||||||
|
@ -104,6 +124,7 @@ enum babel_iface_type {
|
||||||
BABEL_IFACE_TYPE_UNDEF = 0,
|
BABEL_IFACE_TYPE_UNDEF = 0,
|
||||||
BABEL_IFACE_TYPE_WIRED = 1,
|
BABEL_IFACE_TYPE_WIRED = 1,
|
||||||
BABEL_IFACE_TYPE_WIRELESS = 2,
|
BABEL_IFACE_TYPE_WIRELESS = 2,
|
||||||
|
BABEL_IFACE_TYPE_TUNNEL = 3,
|
||||||
BABEL_IFACE_TYPE_MAX
|
BABEL_IFACE_TYPE_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -119,6 +140,8 @@ enum babel_ae_type {
|
||||||
struct babel_config {
|
struct babel_config {
|
||||||
struct proto_config c;
|
struct proto_config c;
|
||||||
list iface_list; /* List of iface configs (struct babel_iface_config) */
|
list iface_list; /* List of iface configs (struct babel_iface_config) */
|
||||||
|
btime metric_decay;
|
||||||
|
uint smooth_recp; /* Reciprocal for exponential metric smoothing */
|
||||||
uint hold_time; /* Time to hold stale entries and unreachable routes */
|
uint hold_time; /* Time to hold stale entries and unreachable routes */
|
||||||
u8 randomize_router_id;
|
u8 randomize_router_id;
|
||||||
|
|
||||||
|
@ -138,6 +161,12 @@ struct babel_iface_config {
|
||||||
uint ihu_interval; /* IHU interval, in us */
|
uint ihu_interval; /* IHU interval, in us */
|
||||||
uint update_interval; /* Update interval, in us */
|
uint update_interval; /* Update interval, in us */
|
||||||
|
|
||||||
|
btime rtt_min; /* rtt above which to start penalising metric */
|
||||||
|
btime rtt_max; /* max rtt metric penalty applied above this */
|
||||||
|
u16 rtt_cost; /* metric penalty to apply at rtt_max */
|
||||||
|
u16 rtt_win_len; /* smoothing windows length */
|
||||||
|
u8 rtt_send; /* whether to send timestamps on this interface */
|
||||||
|
|
||||||
u16 rx_buffer; /* RX buffer size, 0 for MTU */
|
u16 rx_buffer; /* RX buffer size, 0 for MTU */
|
||||||
u16 tx_length; /* TX packet length limit (including headers), 0 for MTU */
|
u16 tx_length; /* TX packet length limit (including headers), 0 for MTU */
|
||||||
int tx_tos;
|
int tx_tos;
|
||||||
|
@ -225,6 +254,14 @@ struct babel_neighbor {
|
||||||
u16 next_hello_seqno;
|
u16 next_hello_seqno;
|
||||||
uint last_hello_int;
|
uint last_hello_int;
|
||||||
|
|
||||||
|
u32 last_tstamp;
|
||||||
|
btime last_tstamp_rcvd;
|
||||||
|
btime srtt;
|
||||||
|
btime *srtt_pool; // an array of btime
|
||||||
|
btime *srtt_pool_sorted;
|
||||||
|
u16 srtt_pool_len; // initial length
|
||||||
|
u16 srtt_poll_idx; // head
|
||||||
|
|
||||||
u32 auth_pc;
|
u32 auth_pc;
|
||||||
u8 auth_passed;
|
u8 auth_passed;
|
||||||
u8 auth_index_len;
|
u8 auth_index_len;
|
||||||
|
@ -262,9 +299,11 @@ struct babel_route {
|
||||||
u16 seqno;
|
u16 seqno;
|
||||||
u16 metric;
|
u16 metric;
|
||||||
u16 advert_metric;
|
u16 advert_metric;
|
||||||
|
u16 smoothed_metric;
|
||||||
u64 router_id;
|
u64 router_id;
|
||||||
ip_addr next_hop;
|
ip_addr next_hop;
|
||||||
btime refresh_time;
|
btime refresh_time;
|
||||||
|
btime smoothed_time;
|
||||||
btime expires;
|
btime expires;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -322,6 +361,8 @@ struct babel_msg_hello {
|
||||||
u16 seqno;
|
u16 seqno;
|
||||||
uint interval;
|
uint interval;
|
||||||
ip_addr sender;
|
ip_addr sender;
|
||||||
|
u32 tstamp;
|
||||||
|
btime pkt_received;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct babel_msg_ihu {
|
struct babel_msg_ihu {
|
||||||
|
@ -331,6 +372,9 @@ struct babel_msg_ihu {
|
||||||
uint interval;
|
uint interval;
|
||||||
ip_addr addr;
|
ip_addr addr;
|
||||||
ip_addr sender;
|
ip_addr sender;
|
||||||
|
u32 tstamp;
|
||||||
|
u32 tstamp_rcvd;
|
||||||
|
btime pkt_received;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct babel_msg_update {
|
struct babel_msg_update {
|
||||||
|
|
|
@ -23,9 +23,10 @@ CF_DEFINES
|
||||||
CF_DECLS
|
CF_DECLS
|
||||||
|
|
||||||
CF_KEYWORDS(BABEL, INTERFACE, METRIC, RXCOST, HELLO, UPDATE, INTERVAL, PORT,
|
CF_KEYWORDS(BABEL, INTERFACE, METRIC, RXCOST, HELLO, UPDATE, INTERVAL, PORT,
|
||||||
TYPE, WIRED, WIRELESS, RX, TX, BUFFER, PRIORITY, LENGTH, CHECK, LINK,
|
TYPE, WIRED, WIRELESS, TUNNEL, RX, TX, BUFFER, PRIORITY, LENGTH, CHECK,
|
||||||
NEXT, HOP, IPV4, IPV6, BABEL_METRIC, SHOW, INTERFACES, NEIGHBORS,
|
LINK, NEXT, HOP, IPV4, IPV6, BABEL_METRIC, SHOW, INTERFACES, NEIGHBORS,
|
||||||
ENTRIES, RANDOMIZE, ROUTER, ID, AUTHENTICATION, NONE, MAC, PERMISSIVE)
|
ENTRIES, RANDOMIZE, ROUTER, ID, AUTHENTICATION, NONE, MAC, PERMISSIVE,
|
||||||
|
RTT, MIN, MAX, DECAY, WINLEN, SEND, TIMESTAMPS)
|
||||||
|
|
||||||
CF_GRAMMAR
|
CF_GRAMMAR
|
||||||
|
|
||||||
|
@ -36,6 +37,13 @@ babel_proto_start: proto_start BABEL
|
||||||
this_proto = proto_config_new(&proto_babel, $1);
|
this_proto = proto_config_new(&proto_babel, $1);
|
||||||
init_list(&BABEL_CFG->iface_list);
|
init_list(&BABEL_CFG->iface_list);
|
||||||
BABEL_CFG->hold_time = 1 S_;
|
BABEL_CFG->hold_time = 1 S_;
|
||||||
|
BABEL_CFG->metric_decay = BABEL_SMOOTHING_DECAY;
|
||||||
|
};
|
||||||
|
|
||||||
|
babel_proto_finish:
|
||||||
|
{
|
||||||
|
if (BABEL_CFG->metric_decay)
|
||||||
|
BABEL_CFG->smooth_recp = BABEL_SMOOTHING_UNIT + BABEL_SMOOTHING_CONSTANT / BABEL_CFG->metric_decay;
|
||||||
};
|
};
|
||||||
|
|
||||||
babel_proto_item:
|
babel_proto_item:
|
||||||
|
@ -43,6 +51,7 @@ babel_proto_item:
|
||||||
| proto_channel
|
| proto_channel
|
||||||
| INTERFACE babel_iface
|
| INTERFACE babel_iface
|
||||||
| RANDOMIZE ROUTER ID bool { BABEL_CFG->randomize_router_id = $4; }
|
| RANDOMIZE ROUTER ID bool { BABEL_CFG->randomize_router_id = $4; }
|
||||||
|
| METRIC DECAY expr_us { BABEL_CFG->metric_decay = $3; if ($3 && (($3 < BABEL_SMOOTHING_STEP) || ($3 > BABEL_SMOOTHING_DECAY_MAX))) cf_error("Metric decay must be 0, or between 1-180s"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
babel_proto_opts:
|
babel_proto_opts:
|
||||||
|
@ -51,7 +60,7 @@ babel_proto_opts:
|
||||||
;
|
;
|
||||||
|
|
||||||
babel_proto:
|
babel_proto:
|
||||||
babel_proto_start proto_name '{' babel_proto_opts '}';
|
babel_proto_start proto_name '{' babel_proto_opts '}' babel_proto_finish;
|
||||||
|
|
||||||
|
|
||||||
babel_iface_start:
|
babel_iface_start:
|
||||||
|
@ -66,6 +75,10 @@ babel_iface_start:
|
||||||
BABEL_IFACE->limit = BABEL_HELLO_LIMIT;
|
BABEL_IFACE->limit = BABEL_HELLO_LIMIT;
|
||||||
BABEL_IFACE->tx_tos = IP_PREC_INTERNET_CONTROL;
|
BABEL_IFACE->tx_tos = IP_PREC_INTERNET_CONTROL;
|
||||||
BABEL_IFACE->tx_priority = sk_priority_control;
|
BABEL_IFACE->tx_priority = sk_priority_control;
|
||||||
|
BABEL_IFACE->rtt_min = BABEL_RTT_MIN;
|
||||||
|
BABEL_IFACE->rtt_max = BABEL_RTT_MAX;
|
||||||
|
BABEL_IFACE->rtt_win_len = BABEL_RTT_WINLEN;
|
||||||
|
BABEL_IFACE->rtt_send = 1;
|
||||||
BABEL_IFACE->check_link = 1;
|
BABEL_IFACE->check_link = 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -85,8 +98,16 @@ babel_iface_finish:
|
||||||
BABEL_IFACE->hello_interval = BABEL_HELLO_INTERVAL_WIRED;
|
BABEL_IFACE->hello_interval = BABEL_HELLO_INTERVAL_WIRED;
|
||||||
if (!BABEL_IFACE->rxcost)
|
if (!BABEL_IFACE->rxcost)
|
||||||
BABEL_IFACE->rxcost = BABEL_RXCOST_WIRED;
|
BABEL_IFACE->rxcost = BABEL_RXCOST_WIRED;
|
||||||
|
if (BABEL_IFACE->type == BABEL_IFACE_TYPE_TUNNEL && !BABEL_IFACE->rtt_cost)
|
||||||
|
BABEL_IFACE->rtt_cost = BABEL_RXCOST_RTT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (BABEL_IFACE->rtt_cost && !BABEL_IFACE->rtt_send)
|
||||||
|
cf_error("Can't set RTT cost when sending timestamps is disabled");
|
||||||
|
|
||||||
|
if (BABEL_IFACE->rtt_min >= BABEL_IFACE->rtt_max)
|
||||||
|
cf_error("Min RTT must be smaller than max RTT");
|
||||||
|
|
||||||
/* Make sure we do not overflow the 16-bit centisec fields */
|
/* Make sure we do not overflow the 16-bit centisec fields */
|
||||||
if (!BABEL_IFACE->update_interval)
|
if (!BABEL_IFACE->update_interval)
|
||||||
BABEL_IFACE->update_interval = MIN_(BABEL_IFACE->hello_interval*BABEL_UPDATE_INTERVAL_FACTOR, BABEL_MAX_INTERVAL);
|
BABEL_IFACE->update_interval = MIN_(BABEL_IFACE->hello_interval*BABEL_UPDATE_INTERVAL_FACTOR, BABEL_MAX_INTERVAL);
|
||||||
|
@ -134,6 +155,7 @@ babel_iface_item:
|
||||||
| LIMIT expr { BABEL_IFACE->limit = $2; if (($2<1) || ($2>16)) cf_error("Limit must be in range 1-16"); }
|
| LIMIT expr { BABEL_IFACE->limit = $2; if (($2<1) || ($2>16)) cf_error("Limit must be in range 1-16"); }
|
||||||
| TYPE WIRED { BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRED; }
|
| TYPE WIRED { BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRED; }
|
||||||
| TYPE WIRELESS { BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRELESS; }
|
| TYPE WIRELESS { BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRELESS; }
|
||||||
|
| TYPE TUNNEL { BABEL_IFACE->type = BABEL_IFACE_TYPE_TUNNEL; }
|
||||||
| HELLO INTERVAL expr_us { BABEL_IFACE->hello_interval = $3; if (($3<BABEL_MIN_INTERVAL) || ($3>BABEL_MAX_INTERVAL)) cf_error("Hello interval must be in range 10 ms - 655 s"); }
|
| HELLO INTERVAL expr_us { BABEL_IFACE->hello_interval = $3; if (($3<BABEL_MIN_INTERVAL) || ($3>BABEL_MAX_INTERVAL)) cf_error("Hello interval must be in range 10 ms - 655 s"); }
|
||||||
| UPDATE INTERVAL expr_us { BABEL_IFACE->update_interval = $3; if (($3<BABEL_MIN_INTERVAL) || ($3>BABEL_MAX_INTERVAL)) cf_error("Update interval must be in range 10 ms - 655 s"); }
|
| UPDATE INTERVAL expr_us { BABEL_IFACE->update_interval = $3; if (($3<BABEL_MIN_INTERVAL) || ($3>BABEL_MAX_INTERVAL)) cf_error("Update interval must be in range 10 ms - 655 s"); }
|
||||||
| RX BUFFER expr { BABEL_IFACE->rx_buffer = $3; if (($3<256) || ($3>65535)) cf_error("RX buffer must be in range 256-65535"); }
|
| RX BUFFER expr { BABEL_IFACE->rx_buffer = $3; if (($3<256) || ($3>65535)) cf_error("RX buffer must be in range 256-65535"); }
|
||||||
|
@ -146,6 +168,11 @@ babel_iface_item:
|
||||||
| AUTHENTICATION NONE { BABEL_IFACE->auth_type = BABEL_AUTH_NONE; }
|
| AUTHENTICATION NONE { BABEL_IFACE->auth_type = BABEL_AUTH_NONE; }
|
||||||
| AUTHENTICATION MAC { BABEL_IFACE->auth_type = BABEL_AUTH_MAC; BABEL_IFACE->auth_permissive = 0; }
|
| AUTHENTICATION MAC { BABEL_IFACE->auth_type = BABEL_AUTH_MAC; BABEL_IFACE->auth_permissive = 0; }
|
||||||
| AUTHENTICATION MAC PERMISSIVE { BABEL_IFACE->auth_type = BABEL_AUTH_MAC; BABEL_IFACE->auth_permissive = 1; }
|
| AUTHENTICATION MAC PERMISSIVE { BABEL_IFACE->auth_type = BABEL_AUTH_MAC; BABEL_IFACE->auth_permissive = 1; }
|
||||||
|
| RTT MIN expr_us { BABEL_IFACE->rtt_min = $3; }
|
||||||
|
| RTT MAX expr_us { BABEL_IFACE->rtt_max = $3; }
|
||||||
|
| RTT COST expr { BABEL_IFACE->rtt_cost = $3; if ($3 >= BABEL_INFINITY) cf_error("RTT cost must be < 65535"); }
|
||||||
|
| RTT WINLEN expr { BABEL_IFACE->rtt_win_len = $3; if (($3 < 1) || ($3 > 65535)) cf_error("RTT winlen must be between 1-65535"); }
|
||||||
|
| SEND TIMESTAMPS bool { BABEL_IFACE->rtt_send = $3; }
|
||||||
| password_list
|
| password_list
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,13 @@ struct babel_tlv_ihu {
|
||||||
u8 addr[0];
|
u8 addr[0];
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
|
struct babel_subtlv_timestamp {
|
||||||
|
u8 type;
|
||||||
|
u8 length;
|
||||||
|
u32 tstamp;
|
||||||
|
u32 tstamp_rcvd; /* only used in IHU */
|
||||||
|
} PACKED;
|
||||||
|
|
||||||
struct babel_tlv_router_id {
|
struct babel_tlv_router_id {
|
||||||
u8 type;
|
u8 type;
|
||||||
u8 length;
|
u8 length;
|
||||||
|
@ -161,6 +168,7 @@ struct babel_parse_state {
|
||||||
const struct babel_tlv_data* (*get_subtlv_data)(u8 type);
|
const struct babel_tlv_data* (*get_subtlv_data)(u8 type);
|
||||||
struct babel_proto *proto;
|
struct babel_proto *proto;
|
||||||
struct babel_iface *ifa;
|
struct babel_iface *ifa;
|
||||||
|
btime received_time;
|
||||||
ip_addr saddr;
|
ip_addr saddr;
|
||||||
ip_addr next_hop_ip4;
|
ip_addr next_hop_ip4;
|
||||||
ip_addr next_hop_ip6;
|
ip_addr next_hop_ip6;
|
||||||
|
@ -170,6 +178,7 @@ struct babel_parse_state {
|
||||||
u8 router_id_seen; /* router_id field is valid */
|
u8 router_id_seen; /* router_id field is valid */
|
||||||
u8 def_ip6_prefix_seen; /* def_ip6_prefix is valid */
|
u8 def_ip6_prefix_seen; /* def_ip6_prefix is valid */
|
||||||
u8 def_ip4_prefix_seen; /* def_ip4_prefix is valid */
|
u8 def_ip4_prefix_seen; /* def_ip4_prefix is valid */
|
||||||
|
u8 hello_tstamp_seen; /* pkt contains a hello timestamp */
|
||||||
u8 current_tlv_endpos; /* End of self-terminating TLVs (offset from start) */
|
u8 current_tlv_endpos; /* End of self-terminating TLVs (offset from start) */
|
||||||
u8 sadr_enabled;
|
u8 sadr_enabled;
|
||||||
u8 is_unicast;
|
u8 is_unicast;
|
||||||
|
@ -334,6 +343,7 @@ static int babel_read_update(struct babel_tlv *hdr, union babel_msg *msg, struct
|
||||||
static int babel_read_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
|
static int babel_read_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
|
||||||
static int babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
|
static int babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
|
||||||
static int babel_read_source_prefix(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
|
static int babel_read_source_prefix(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
|
||||||
|
static int babel_read_timestamp(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
|
||||||
|
|
||||||
static uint babel_write_ack(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
|
static uint babel_write_ack(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
|
||||||
static uint babel_write_hello(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
|
static uint babel_write_hello(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
|
||||||
|
@ -342,6 +352,7 @@ static uint babel_write_update(struct babel_tlv *hdr, union babel_msg *msg, stru
|
||||||
static uint babel_write_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
|
static uint babel_write_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
|
||||||
static uint babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
|
static uint babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
|
||||||
static int babel_write_source_prefix(struct babel_tlv *hdr, net_addr *net, uint max_len);
|
static int babel_write_source_prefix(struct babel_tlv *hdr, net_addr *net, uint max_len);
|
||||||
|
static int babel_write_timestamp(struct babel_tlv *hdr, u32 tstamp, u32 tstamp_rcvd, uint max_len);
|
||||||
|
|
||||||
static const struct babel_tlv_data tlv_data[BABEL_TLV_MAX] = {
|
static const struct babel_tlv_data tlv_data[BABEL_TLV_MAX] = {
|
||||||
[BABEL_TLV_ACK_REQ] = {
|
[BABEL_TLV_ACK_REQ] = {
|
||||||
|
@ -417,6 +428,13 @@ static const struct babel_tlv_data *get_packet_tlv_data(u8 type)
|
||||||
return type < sizeof(tlv_data) / sizeof(*tlv_data) ? &tlv_data[type] : NULL;
|
return type < sizeof(tlv_data) / sizeof(*tlv_data) ? &tlv_data[type] : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct babel_tlv_data timestamp_tlv_data = {
|
||||||
|
sizeof(struct babel_subtlv_timestamp),
|
||||||
|
babel_read_timestamp,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
static const struct babel_tlv_data source_prefix_tlv_data = {
|
static const struct babel_tlv_data source_prefix_tlv_data = {
|
||||||
sizeof(struct babel_subtlv_source_prefix),
|
sizeof(struct babel_subtlv_source_prefix),
|
||||||
babel_read_source_prefix,
|
babel_read_source_prefix,
|
||||||
|
@ -428,6 +446,8 @@ static const struct babel_tlv_data *get_packet_subtlv_data(u8 type)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
|
case BABEL_SUBTLV_TIMESTAMP:
|
||||||
|
return ×tamp_tlv_data;
|
||||||
case BABEL_SUBTLV_SOURCE_PREFIX:
|
case BABEL_SUBTLV_SOURCE_PREFIX:
|
||||||
return &source_prefix_tlv_data;
|
return &source_prefix_tlv_data;
|
||||||
|
|
||||||
|
@ -489,16 +509,34 @@ babel_read_hello(struct babel_tlv *hdr, union babel_msg *m,
|
||||||
|
|
||||||
static uint
|
static uint
|
||||||
babel_write_hello(struct babel_tlv *hdr, union babel_msg *m,
|
babel_write_hello(struct babel_tlv *hdr, union babel_msg *m,
|
||||||
struct babel_write_state *state UNUSED, uint max_len UNUSED)
|
struct babel_write_state *state UNUSED, uint max_len)
|
||||||
{
|
{
|
||||||
struct babel_tlv_hello *tlv = (void *) hdr;
|
struct babel_tlv_hello *tlv = (void *) hdr;
|
||||||
struct babel_msg_hello *msg = &m->hello;
|
struct babel_msg_hello *msg = &m->hello;
|
||||||
|
uint len = sizeof(struct babel_tlv_hello);
|
||||||
|
|
||||||
TLV_HDR0(tlv, BABEL_TLV_HELLO);
|
TLV_HDR0(tlv, BABEL_TLV_HELLO);
|
||||||
put_u16(&tlv->seqno, msg->seqno);
|
put_u16(&tlv->seqno, msg->seqno);
|
||||||
put_time16(&tlv->interval, msg->interval);
|
put_time16(&tlv->interval, msg->interval);
|
||||||
|
|
||||||
return sizeof(struct babel_tlv_hello);
|
if (msg->tstamp)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* There can be a substantial delay between when the babel_msg was created
|
||||||
|
* and when it is serialised. We don't want this included in the RTT
|
||||||
|
* measurement, so replace the timestamp with the current time to get as
|
||||||
|
* close as possible to on-wire time for the packet.
|
||||||
|
*/
|
||||||
|
u32 tstamp = current_time_now() TO_US;
|
||||||
|
|
||||||
|
int l = babel_write_timestamp(hdr, tstamp, 0, max_len);
|
||||||
|
if (l < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
len += l;
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -556,6 +594,7 @@ babel_write_ihu(struct babel_tlv *hdr, union babel_msg *m,
|
||||||
{
|
{
|
||||||
struct babel_tlv_ihu *tlv = (void *) hdr;
|
struct babel_tlv_ihu *tlv = (void *) hdr;
|
||||||
struct babel_msg_ihu *msg = &m->ihu;
|
struct babel_msg_ihu *msg = &m->ihu;
|
||||||
|
uint len = sizeof(*tlv);
|
||||||
|
|
||||||
if (ipa_is_link_local(msg->addr) && max_len < sizeof(struct babel_tlv_ihu) + 8)
|
if (ipa_is_link_local(msg->addr) && max_len < sizeof(struct babel_tlv_ihu) + 8)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -567,12 +606,24 @@ babel_write_ihu(struct babel_tlv *hdr, union babel_msg *m,
|
||||||
if (!ipa_is_link_local(msg->addr))
|
if (!ipa_is_link_local(msg->addr))
|
||||||
{
|
{
|
||||||
tlv->ae = BABEL_AE_WILDCARD;
|
tlv->ae = BABEL_AE_WILDCARD;
|
||||||
return sizeof(struct babel_tlv_ihu);
|
goto out;
|
||||||
}
|
}
|
||||||
put_ip6_ll(&tlv->addr, msg->addr);
|
put_ip6_ll(&tlv->addr, msg->addr);
|
||||||
tlv->ae = BABEL_AE_IP6_LL;
|
tlv->ae = BABEL_AE_IP6_LL;
|
||||||
hdr->length += 8;
|
hdr->length += 8;
|
||||||
return sizeof(struct babel_tlv_ihu) + 8;
|
len += 8;
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (msg->tstamp)
|
||||||
|
{
|
||||||
|
int l = babel_write_timestamp(hdr, msg->tstamp, msg->tstamp_rcvd, max_len);
|
||||||
|
if (l < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
len += l;
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -1200,6 +1251,66 @@ babel_write_source_prefix(struct babel_tlv *hdr, net_addr *n, uint max_len)
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
babel_read_timestamp(struct babel_tlv *hdr, union babel_msg *msg,
|
||||||
|
struct babel_parse_state *state)
|
||||||
|
{
|
||||||
|
struct babel_subtlv_timestamp *tlv = (void *) hdr;
|
||||||
|
|
||||||
|
switch (msg->type)
|
||||||
|
{
|
||||||
|
case BABEL_TLV_HELLO:
|
||||||
|
if (tlv->length < 4)
|
||||||
|
return PARSE_ERROR;
|
||||||
|
|
||||||
|
msg->hello.tstamp = get_u32(&tlv->tstamp);
|
||||||
|
msg->hello.pkt_received = state->received_time;
|
||||||
|
state->hello_tstamp_seen = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BABEL_TLV_IHU:
|
||||||
|
if (tlv->length < 8)
|
||||||
|
return PARSE_ERROR;
|
||||||
|
|
||||||
|
/* RTT calculation relies on a Hello always being present with an IHU */
|
||||||
|
if (!state->hello_tstamp_seen)
|
||||||
|
break;
|
||||||
|
|
||||||
|
msg->ihu.tstamp = get_u32(&tlv->tstamp);
|
||||||
|
msg->ihu.tstamp_rcvd = get_u32(&tlv->tstamp_rcvd);
|
||||||
|
msg->ihu.pkt_received = state->received_time;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PARSE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
babel_write_timestamp(struct babel_tlv *hdr, u32 tstamp, u32 tstamp_rcvd, uint max_len)
|
||||||
|
{
|
||||||
|
struct babel_subtlv_timestamp *tlv = (void *) NEXT_TLV(hdr);
|
||||||
|
uint len = sizeof(*tlv);
|
||||||
|
|
||||||
|
if (hdr->type == BABEL_TLV_HELLO)
|
||||||
|
len -= 4;
|
||||||
|
|
||||||
|
if (len > max_len)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
TLV_HDR(tlv, BABEL_SUBTLV_TIMESTAMP, len);
|
||||||
|
hdr->length += len;
|
||||||
|
|
||||||
|
put_u32(&tlv->tstamp, tstamp);
|
||||||
|
|
||||||
|
if (hdr->type == BABEL_TLV_IHU)
|
||||||
|
put_u32(&tlv->tstamp_rcvd, tstamp_rcvd);
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
babel_read_subtlvs(struct babel_tlv *hdr,
|
babel_read_subtlvs(struct babel_tlv *hdr,
|
||||||
union babel_msg *msg,
|
union babel_msg *msg,
|
||||||
|
@ -1469,6 +1580,13 @@ babel_process_packet(struct babel_iface *ifa,
|
||||||
.saddr = saddr,
|
.saddr = saddr,
|
||||||
.next_hop_ip6 = saddr,
|
.next_hop_ip6 = saddr,
|
||||||
.sadr_enabled = babel_sadr_enabled(p),
|
.sadr_enabled = babel_sadr_enabled(p),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The core updates current_time() after returning from poll(), so this is
|
||||||
|
* actually the time the packet was received, even though there may have
|
||||||
|
* been a bit of delay before we got to process it
|
||||||
|
*/
|
||||||
|
.received_time = current_time(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if ((pkt->magic != BABEL_MAGIC) || (pkt->version != BABEL_VERSION))
|
if ((pkt->magic != BABEL_MAGIC) || (pkt->version != BABEL_VERSION))
|
||||||
|
|
Loading…
Reference in a new issue