Compare commits
4 commits
master
...
babel-rtt-
Author | SHA1 | Date | |
---|---|---|---|
|
4c582913ec | ||
|
56841eecbc | ||
|
44421ba7d4 | ||
|
8f9a091d30 |
7 changed files with 467 additions and 35 deletions
|
@ -1865,8 +1865,9 @@ protocol babel [<name>] {
|
|||
ipv4 { <channel config> };
|
||||
ipv6 [sadr] { <channel config> };
|
||||
randomize router id <switch>;
|
||||
metric decay <time>;
|
||||
interface <interface pattern> {
|
||||
type <wired|wireless>;
|
||||
type <wired|wireless|tunnel>;
|
||||
rxcost <number>;
|
||||
limit <number>;
|
||||
hello interval <time>;
|
||||
|
@ -1879,6 +1880,11 @@ protocol babel [<name>] {
|
|||
check link <switch>;
|
||||
next hop ipv4 <address>;
|
||||
next hop ipv6 <address>;
|
||||
rtt cost <number>;
|
||||
rtt min <time>;
|
||||
rtt max <time>;
|
||||
rtt decay <number>;
|
||||
send timestamps <switch>;
|
||||
authentication none|mac [permissive];
|
||||
password "<text>";
|
||||
password "<text>" {
|
||||
|
@ -1909,15 +1915,27 @@ protocol babel [<name>] {
|
|||
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.
|
||||
|
||||
<tag><label id="babel-type">type wired|wireless </tag>
|
||||
This option specifies the interface type: Wired or wireless. 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
|
||||
<tag><label id="babel-metric-decay">metric decay <m/time/ s</tag>
|
||||
The metric smoothing decay time. When route metrics vary (because of
|
||||
varying quality of a wireless link, or varying RTT when timestamps are
|
||||
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
|
||||
the metrics of routes discovered over this interface. This technique will
|
||||
gradually degrade the metric of routes when packets are lost rather than
|
||||
the more binary up/down mechanism of wired type links. Default:
|
||||
<cf/wired/.
|
||||
the more binary up/down mechanism of wired type links. A tunnel is like a
|
||||
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>
|
||||
This option specifies the nominal RX cost of the interface. The effective
|
||||
|
@ -1983,6 +2001,37 @@ protocol babel [<name>] {
|
|||
source for Babel packets will be used. In normal operation, it should not
|
||||
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-decay">rtt decay <m/number/</tag>
|
||||
The decay factor used for the exponentional moving average of the RTT
|
||||
samples from each neighbour, in units of 1/256. Higher values discards old
|
||||
RTT samples faster. Must be between 1 and 256. Default: 42
|
||||
|
||||
<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>
|
||||
Selects authentication method to be used. <cf/none/ means that packets
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
current_real_time(void)
|
||||
{
|
||||
|
|
|
@ -44,6 +44,7 @@ static inline timer *timers_first(struct timeloop *loop)
|
|||
extern struct timeloop main_timeloop;
|
||||
|
||||
btime current_time(void);
|
||||
btime current_time_now(void);
|
||||
btime current_real_time(void);
|
||||
|
||||
//#define now (current_time() TO_S)
|
||||
|
|
|
@ -134,6 +134,103 @@ babel_expire_sources(struct babel_proto *p, 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 *
|
||||
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);
|
||||
|
||||
if (r)
|
||||
if (r) {
|
||||
babel_update_smoothed_metric(p, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
WALK_LIST(sr, e->requests)
|
||||
if (sr->router_id == router_id)
|
||||
if (sr->router_id == router_id && sr->nbr == nbr)
|
||||
{
|
||||
/* Found matching or newer */
|
||||
if (ge_mod64k(sr->seqno, seqno) && seqno_request_valid(sr))
|
||||
|
@ -312,7 +411,8 @@ babel_add_seqno_request(struct babel_proto *p, struct babel_entry *e,
|
|||
|
||||
/* Found older */
|
||||
rem_node(NODE sr);
|
||||
rem_node(&sr->nbr_node);
|
||||
if (sr->nbr)
|
||||
rem_node(&sr->nbr_node);
|
||||
|
||||
goto found;
|
||||
}
|
||||
|
@ -349,17 +449,20 @@ static int
|
|||
babel_satisfy_seqno_request(struct babel_proto *p, struct babel_entry *e,
|
||||
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))
|
||||
{
|
||||
/* 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);
|
||||
return 1;
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -570,6 +673,7 @@ babel_update_cost(struct babel_neighbor *nbr)
|
|||
switch (cf->type)
|
||||
{
|
||||
case BABEL_IFACE_TYPE_WIRED:
|
||||
case BABEL_IFACE_TYPE_TUNNEL:
|
||||
/* 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 */
|
||||
|
@ -598,6 +702,25 @@ babel_update_cost(struct babel_neighbor *nbr)
|
|||
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:
|
||||
/* If RX cost changed, send IHU with next Hello */
|
||||
if (rxcost != nbr->rxcost)
|
||||
|
@ -617,7 +740,7 @@ done:
|
|||
struct babel_route *r; node *n;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -741,8 +864,7 @@ babel_select_route(struct babel_proto *p, struct babel_entry *e, struct babel_ro
|
|||
/* Shortcut if only non-best was modified */
|
||||
if (mod && (mod != best))
|
||||
{
|
||||
/* Either select modified route, or keep old best route */
|
||||
if ((mod->metric < (best ? best->metric : BABEL_INFINITY)) && mod->feasible)
|
||||
if (babel_route_better(p, mod, best))
|
||||
best = mod;
|
||||
else
|
||||
return;
|
||||
|
@ -753,17 +875,24 @@ babel_select_route(struct babel_proto *p, struct babel_entry *e, struct babel_ro
|
|||
if (!best || (best->metric == BABEL_INFINITY) || !best->feasible)
|
||||
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 */
|
||||
WALK_LIST(r, e->routes)
|
||||
if ((r->metric < (best ? best->metric : BABEL_INFINITY)) && r->feasible)
|
||||
if (babel_route_better(p, r, best))
|
||||
best = r;
|
||||
}
|
||||
|
||||
if (best)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
@ -812,6 +941,12 @@ babel_build_ihu(union babel_msg *msg, struct babel_iface *ifa, struct babel_neig
|
|||
msg->ihu.rxcost = n->rxcost;
|
||||
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",
|
||||
msg->ihu.addr, msg->ihu.rxcost, (btime) msg->ihu.interval);
|
||||
}
|
||||
|
@ -851,6 +986,9 @@ babel_send_hello(struct babel_iface *ifa, uint interval)
|
|||
msg.hello.seqno = ifa->hello_seqno++;
|
||||
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",
|
||||
ifa->ifname, msg.hello.seqno, (btime) msg.hello.interval);
|
||||
|
||||
|
@ -1146,14 +1284,26 @@ babel_handle_hello(union babel_msg *m, struct babel_iface *ifa)
|
|||
msg->seqno, (btime) msg->interval);
|
||||
|
||||
struct babel_neighbor *n = babel_get_neighbor(ifa, msg->sender);
|
||||
struct babel_iface_config *cf = n->ifa->cf;
|
||||
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_cost(n);
|
||||
|
||||
/* Speed up session establishment by sending IHU immediately */
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1172,6 +1322,39 @@ babel_handle_ihu(union babel_msg *m, struct babel_iface *ifa)
|
|||
struct babel_neighbor *n = babel_get_neighbor(ifa, msg->sender);
|
||||
n->txcost = msg->rxcost;
|
||||
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)
|
||||
{
|
||||
uint decay = n->ifa->cf->rtt_decay;
|
||||
|
||||
n->srtt = (decay * rtt_sample + (256 - decay) * n->srtt) / 256;
|
||||
}
|
||||
else
|
||||
n->srtt = rtt_sample;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1288,9 +1471,9 @@ babel_handle_update(union babel_msg *m, struct babel_iface *ifa)
|
|||
return;
|
||||
|
||||
/* Last paragraph above - update the entry */
|
||||
babel_update_metric(p, r, metric);
|
||||
r->feasible = feasible;
|
||||
r->seqno = msg->seqno;
|
||||
r->metric = metric;
|
||||
r->advert_metric = msg->metric;
|
||||
r->router_id = msg->router_id;
|
||||
r->next_hop = msg->next_hop;
|
||||
|
@ -2087,8 +2270,8 @@ babel_show_neighbors(struct proto *P, const char *iff)
|
|||
}
|
||||
|
||||
cli_msg(-1024, "%s:", p->p.name);
|
||||
cli_msg(-1024, "%-25s %-10s %6s %6s %6s %7s %4s",
|
||||
"IP address", "Interface", "Metric", "Routes", "Hellos", "Expires", "Auth");
|
||||
cli_msg(-1024, "%-25s %-10s %6s %6s %6s %7s %4s %11s",
|
||||
"IP address", "Interface", "Metric", "Routes", "Hellos", "Expires", "Auth", "RTT");
|
||||
|
||||
WALK_LIST(ifa, p->interfaces)
|
||||
{
|
||||
|
@ -2103,9 +2286,10 @@ babel_show_neighbors(struct proto *P, const char *iff)
|
|||
|
||||
uint hellos = u32_popcount(n->hello_map);
|
||||
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->auth_passed ? "Yes" : "No");
|
||||
n->auth_passed ? "Yes" : "No",
|
||||
n->srtt/1000, n->srtt%1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,10 +50,28 @@
|
|||
#define BABEL_GARBAGE_INTERVAL (300 S_)
|
||||
#define BABEL_RXCOST_WIRED 96
|
||||
#define BABEL_RXCOST_WIRELESS 256
|
||||
#define BABEL_RXCOST_RTT 96
|
||||
#define BABEL_INITIAL_HOP_COUNT 255
|
||||
#define BABEL_MAX_SEND_INTERVAL 5 /* Unused ? */
|
||||
#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_DECAY 42
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
#define BABEL_TIME_UNITS 10000 /* On-wire times are counted in centiseconds */
|
||||
#define BABEL_MIN_INTERVAL (0x0001 * BABEL_TIME_UNITS)
|
||||
|
@ -93,6 +111,8 @@ enum babel_tlv_type {
|
|||
enum babel_subtlv_type {
|
||||
BABEL_SUBTLV_PAD1 = 0,
|
||||
BABEL_SUBTLV_PADN = 1,
|
||||
BABEL_SUBTLV_DIVERSITY = 2, /* we don't support this */
|
||||
BABEL_SUBTLV_TIMESTAMP = 3,
|
||||
|
||||
/* Mandatory subtlvs */
|
||||
BABEL_SUBTLV_SOURCE_PREFIX = 128,
|
||||
|
@ -103,6 +123,7 @@ enum babel_iface_type {
|
|||
BABEL_IFACE_TYPE_UNDEF = 0,
|
||||
BABEL_IFACE_TYPE_WIRED = 1,
|
||||
BABEL_IFACE_TYPE_WIRELESS = 2,
|
||||
BABEL_IFACE_TYPE_TUNNEL = 3,
|
||||
BABEL_IFACE_TYPE_MAX
|
||||
};
|
||||
|
||||
|
@ -118,6 +139,8 @@ enum babel_ae_type {
|
|||
struct babel_config {
|
||||
struct proto_config c;
|
||||
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 */
|
||||
u8 randomize_router_id;
|
||||
|
||||
|
@ -137,6 +160,12 @@ struct babel_iface_config {
|
|||
uint ihu_interval; /* IHU 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_decay; /* decay of neighbour RTT (units of 1/256) */
|
||||
u8 rtt_send; /* whether to send timestamps on this interface */
|
||||
|
||||
u16 rx_buffer; /* RX buffer size, 0 for MTU */
|
||||
u16 tx_length; /* TX packet length limit (including headers), 0 for MTU */
|
||||
int tx_tos;
|
||||
|
@ -224,6 +253,10 @@ struct babel_neighbor {
|
|||
u16 next_hello_seqno;
|
||||
uint last_hello_int;
|
||||
|
||||
u32 last_tstamp;
|
||||
btime last_tstamp_rcvd;
|
||||
btime srtt;
|
||||
|
||||
u32 auth_pc;
|
||||
u8 auth_passed;
|
||||
u8 auth_index_len;
|
||||
|
@ -261,9 +294,11 @@ struct babel_route {
|
|||
u16 seqno;
|
||||
u16 metric;
|
||||
u16 advert_metric;
|
||||
u16 smoothed_metric;
|
||||
u64 router_id;
|
||||
ip_addr next_hop;
|
||||
btime refresh_time;
|
||||
btime smoothed_time;
|
||||
btime expires;
|
||||
};
|
||||
|
||||
|
@ -321,6 +356,8 @@ struct babel_msg_hello {
|
|||
u16 seqno;
|
||||
uint interval;
|
||||
ip_addr sender;
|
||||
u32 tstamp;
|
||||
btime pkt_received;
|
||||
};
|
||||
|
||||
struct babel_msg_ihu {
|
||||
|
@ -330,6 +367,9 @@ struct babel_msg_ihu {
|
|||
uint interval;
|
||||
ip_addr addr;
|
||||
ip_addr sender;
|
||||
u32 tstamp;
|
||||
u32 tstamp_rcvd;
|
||||
btime pkt_received;
|
||||
};
|
||||
|
||||
struct babel_msg_update {
|
||||
|
|
|
@ -23,9 +23,10 @@ CF_DEFINES
|
|||
CF_DECLS
|
||||
|
||||
CF_KEYWORDS(BABEL, INTERFACE, METRIC, RXCOST, HELLO, UPDATE, INTERVAL, PORT,
|
||||
TYPE, WIRED, WIRELESS, RX, TX, BUFFER, PRIORITY, LENGTH, CHECK, LINK,
|
||||
NEXT, HOP, IPV4, IPV6, BABEL_METRIC, SHOW, INTERFACES, NEIGHBORS,
|
||||
ENTRIES, RANDOMIZE, ROUTER, ID, AUTHENTICATION, NONE, MAC, PERMISSIVE)
|
||||
TYPE, WIRED, WIRELESS, TUNNEL, RX, TX, BUFFER, PRIORITY, LENGTH, CHECK,
|
||||
LINK, NEXT, HOP, IPV4, IPV6, BABEL_METRIC, SHOW, INTERFACES, NEIGHBORS,
|
||||
ENTRIES, RANDOMIZE, ROUTER, ID, AUTHENTICATION, NONE, MAC, PERMISSIVE,
|
||||
RTT, MIN, MAX, DECAY, SEND, TIMESTAMPS)
|
||||
|
||||
CF_GRAMMAR
|
||||
|
||||
|
@ -36,6 +37,13 @@ babel_proto_start: proto_start BABEL
|
|||
this_proto = proto_config_new(&proto_babel, $1);
|
||||
init_list(&BABEL_CFG->iface_list);
|
||||
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:
|
||||
|
@ -43,6 +51,7 @@ babel_proto_item:
|
|||
| proto_channel
|
||||
| INTERFACE babel_iface
|
||||
| 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:
|
||||
|
@ -51,7 +60,7 @@ babel_proto_opts:
|
|||
;
|
||||
|
||||
babel_proto:
|
||||
babel_proto_start proto_name '{' babel_proto_opts '}';
|
||||
babel_proto_start proto_name '{' babel_proto_opts '}' babel_proto_finish;
|
||||
|
||||
|
||||
babel_iface_start:
|
||||
|
@ -66,6 +75,10 @@ babel_iface_start:
|
|||
BABEL_IFACE->limit = BABEL_HELLO_LIMIT;
|
||||
BABEL_IFACE->tx_tos = IP_PREC_INTERNET_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_decay = BABEL_RTT_DECAY;
|
||||
BABEL_IFACE->rtt_send = 1;
|
||||
BABEL_IFACE->check_link = 1;
|
||||
};
|
||||
|
||||
|
@ -85,8 +98,16 @@ babel_iface_finish:
|
|||
BABEL_IFACE->hello_interval = BABEL_HELLO_INTERVAL_WIRED;
|
||||
if (!BABEL_IFACE->rxcost)
|
||||
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 */
|
||||
if (!BABEL_IFACE->update_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"); }
|
||||
| TYPE WIRED { BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRED; }
|
||||
| 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"); }
|
||||
| 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"); }
|
||||
|
@ -146,6 +168,11 @@ babel_iface_item:
|
|||
| 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 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 DECAY expr { BABEL_IFACE->rtt_decay = $3; if (($3 < 1) || ($3 > 256)) cf_error("RTT decay must be between 1-256"); }
|
||||
| SEND TIMESTAMPS bool { BABEL_IFACE->rtt_send = $3; }
|
||||
| password_list
|
||||
;
|
||||
|
||||
|
|
|
@ -58,6 +58,13 @@ struct babel_tlv_ihu {
|
|||
u8 addr[0];
|
||||
} PACKED;
|
||||
|
||||
struct babel_subtlv_timestamp {
|
||||
u8 type;
|
||||
u8 length;
|
||||
u32 tstamp;
|
||||
u32 tstamp_rcvd; /* only used in IHU */
|
||||
} PACKED;
|
||||
|
||||
struct babel_tlv_router_id {
|
||||
u8 type;
|
||||
u8 length;
|
||||
|
@ -161,6 +168,7 @@ struct babel_parse_state {
|
|||
const struct babel_tlv_data* (*get_subtlv_data)(u8 type);
|
||||
struct babel_proto *proto;
|
||||
struct babel_iface *ifa;
|
||||
btime received_time;
|
||||
ip_addr saddr;
|
||||
ip_addr next_hop_ip4;
|
||||
ip_addr next_hop_ip6;
|
||||
|
@ -170,6 +178,7 @@ struct babel_parse_state {
|
|||
u8 router_id_seen; /* router_id field is valid */
|
||||
u8 def_ip6_prefix_seen; /* def_ip6_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 sadr_enabled;
|
||||
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_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_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_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_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_timestamp(struct babel_tlv *hdr, u32 tstamp, u32 tstamp_rcvd, uint max_len);
|
||||
|
||||
static const struct babel_tlv_data tlv_data[BABEL_TLV_MAX] = {
|
||||
[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;
|
||||
}
|
||||
|
||||
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 = {
|
||||
sizeof(struct babel_subtlv_source_prefix),
|
||||
babel_read_source_prefix,
|
||||
|
@ -428,6 +446,8 @@ static const struct babel_tlv_data *get_packet_subtlv_data(u8 type)
|
|||
{
|
||||
switch (type)
|
||||
{
|
||||
case BABEL_SUBTLV_TIMESTAMP:
|
||||
return ×tamp_tlv_data;
|
||||
case BABEL_SUBTLV_SOURCE_PREFIX:
|
||||
return &source_prefix_tlv_data;
|
||||
|
||||
|
@ -489,16 +509,34 @@ babel_read_hello(struct babel_tlv *hdr, union babel_msg *m,
|
|||
|
||||
static uint
|
||||
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_msg_hello *msg = &m->hello;
|
||||
uint len = sizeof(struct babel_tlv_hello);
|
||||
|
||||
TLV_HDR0(tlv, BABEL_TLV_HELLO);
|
||||
put_u16(&tlv->seqno, msg->seqno);
|
||||
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
|
||||
|
@ -556,6 +594,7 @@ babel_write_ihu(struct babel_tlv *hdr, union babel_msg *m,
|
|||
{
|
||||
struct babel_tlv_ihu *tlv = (void *) hdr;
|
||||
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)
|
||||
return 0;
|
||||
|
@ -567,12 +606,24 @@ babel_write_ihu(struct babel_tlv *hdr, union babel_msg *m,
|
|||
if (!ipa_is_link_local(msg->addr))
|
||||
{
|
||||
tlv->ae = BABEL_AE_WILDCARD;
|
||||
return sizeof(struct babel_tlv_ihu);
|
||||
goto out;
|
||||
}
|
||||
put_ip6_ll(&tlv->addr, msg->addr);
|
||||
tlv->ae = BABEL_AE_IP6_LL;
|
||||
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
|
||||
|
@ -1200,6 +1251,66 @@ babel_write_source_prefix(struct babel_tlv *hdr, net_addr *n, uint max_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
|
||||
babel_read_subtlvs(struct babel_tlv *hdr,
|
||||
union babel_msg *msg,
|
||||
|
@ -1470,6 +1581,13 @@ babel_process_packet(struct babel_iface *ifa,
|
|||
.saddr = saddr,
|
||||
.next_hop_ip6 = saddr,
|
||||
.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))
|
||||
|
|
Loading…
Reference in a new issue