Babel: Revamp cost computation and run route selection when cost change
Also fix several minor bugs and add 'limit' option for k-out-of-j link sensing strategy. Change default from 8-of-16 to 12-of-16. Change IHU expiry factor from 1.5 to 3.5 (as in RFC 6126).
This commit is contained in:
parent
f00221fadb
commit
b47eaefe12
4 changed files with 170 additions and 108 deletions
|
@ -1616,6 +1616,7 @@ protocol babel [<name>] {
|
||||||
interface <interface pattern> {
|
interface <interface pattern> {
|
||||||
type <wired|wireless>;
|
type <wired|wireless>;
|
||||||
rxcost <number>;
|
rxcost <number>;
|
||||||
|
limit <number>;
|
||||||
hello interval <number>;
|
hello interval <number>;
|
||||||
update interval <number>;
|
update interval <number>;
|
||||||
port <number>;
|
port <number>;
|
||||||
|
@ -1632,23 +1633,34 @@ protocol babel [<name>] {
|
||||||
|
|
||||||
<descrip>
|
<descrip>
|
||||||
<tag><label id="babel-type">type wired|wireless </tag>
|
<tag><label id="babel-type">type wired|wireless </tag>
|
||||||
This option specifies the interface type: Wired or wireless. Wired
|
This option specifies the interface type: Wired or wireless. On wired
|
||||||
interfaces are considered more reliable, and so the default hello
|
interfaces a neighbor is considered unreachable after a small number of
|
||||||
interval is higher, and a neighbour is considered unreachable after only
|
Hello packets are lost, as described by <cf/limit/ option. On wireless
|
||||||
a small number of "hello" packets are lost. On wireless interfaces,
|
interfaces the ETX link quality estimation technique is used to compute
|
||||||
hello packets are sent more often, and the ETX link quality estimation
|
the metrics of routes discovered over this interface. This technique will
|
||||||
technique is used to compute the metrics of routes discovered over this
|
gradually degrade the metric of routes when packets are lost rather than
|
||||||
interface. This technique will gradually degrade the metric of routes
|
the more binary up/down mechanism of wired type links. Default:
|
||||||
when packets are lost rather than the more binary up/down mechanism of
|
<cf/wired/.
|
||||||
wired type links. Default: <cf/wired/.
|
|
||||||
|
|
||||||
<tag><label id="babel-rxcost">rxcost <m/num/</tag>
|
<tag><label id="babel-rxcost">rxcost <m/num/</tag>
|
||||||
This specifies the RX cost of the interface. The route metrics will be
|
This option specifies the nominal RX cost of the interface. The effective
|
||||||
computed from this value with a mechanism determined by the interface
|
neighbor costs for route metrics will be computed from this value with a
|
||||||
<cf/type/. Default: 96 for wired interfaces, 256 for wireless.
|
mechanism determined by the interface <cf/type/. Note that in contrast to
|
||||||
|
other routing protocols like RIP or OSPF, the <cf/rxcost/ specifies the
|
||||||
|
cost of RX instead of TX, so it affects primarily neighbors' route
|
||||||
|
selection and not local route selection. Default: 96 for wired interfaces,
|
||||||
|
256 for wireless.
|
||||||
|
|
||||||
|
<tag><label id="babel-limit">limit <m/num/</tag>
|
||||||
|
BIRD keeps track of received Hello messages from each neighbor to
|
||||||
|
establish neighbor reachability. For wired type interfaces, this option
|
||||||
|
specifies how many of last 16 hellos have to be correctly received in
|
||||||
|
order to neighbor is assumed to be up. The option is ignored on wireless
|
||||||
|
type interfaces, where gradual cost degradation is used instead of sharp
|
||||||
|
limit. Default: 12.
|
||||||
|
|
||||||
<tag><label id="babel-hello">hello interval <m/num/</tag>
|
<tag><label id="babel-hello">hello interval <m/num/</tag>
|
||||||
Interval at which periodic "hello" messages are sent on this interface,
|
Interval at which periodic Hello messages are sent on this interface,
|
||||||
in seconds. Default: 4 seconds.
|
in seconds. Default: 4 seconds.
|
||||||
|
|
||||||
<tag><label id="babel-update">update interval <m/num/</tag>
|
<tag><label id="babel-update">update interval <m/num/</tag>
|
||||||
|
|
|
@ -57,6 +57,7 @@ static int babel_cache_seqno_request(struct babel_proto *p, net_addr *n, u64 ro
|
||||||
static void babel_trigger_iface_update(struct babel_iface *ifa);
|
static void babel_trigger_iface_update(struct babel_iface *ifa);
|
||||||
static void babel_trigger_update(struct babel_proto *p);
|
static void babel_trigger_update(struct babel_proto *p);
|
||||||
static void babel_send_seqno_request(struct babel_entry *e);
|
static void babel_send_seqno_request(struct babel_entry *e);
|
||||||
|
static void babel_update_cost(struct babel_neighbor *n);
|
||||||
static inline void babel_kick_timer(struct babel_proto *p);
|
static inline void babel_kick_timer(struct babel_proto *p);
|
||||||
static inline void babel_iface_kick_timer(struct babel_iface *ifa);
|
static inline void babel_iface_kick_timer(struct babel_iface *ifa);
|
||||||
|
|
||||||
|
@ -208,7 +209,7 @@ babel_expire_route(struct babel_route *r)
|
||||||
|
|
||||||
if (r->metric < BABEL_INFINITY)
|
if (r->metric < BABEL_INFINITY)
|
||||||
{
|
{
|
||||||
r->metric = BABEL_INFINITY;
|
r->metric = r->advert_metric = BABEL_INFINITY;
|
||||||
r->expires = current_time() + r->expiry_interval;
|
r->expires = current_time() + r->expiry_interval;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -300,15 +301,20 @@ babel_find_neighbor(struct babel_iface *ifa, ip_addr addr)
|
||||||
static struct babel_neighbor *
|
static struct babel_neighbor *
|
||||||
babel_get_neighbor(struct babel_iface *ifa, ip_addr addr)
|
babel_get_neighbor(struct babel_iface *ifa, ip_addr addr)
|
||||||
{
|
{
|
||||||
|
struct babel_proto *p = ifa->proto;
|
||||||
struct babel_neighbor *nbr = babel_find_neighbor(ifa, addr);
|
struct babel_neighbor *nbr = babel_find_neighbor(ifa, addr);
|
||||||
|
|
||||||
if (nbr)
|
if (nbr)
|
||||||
return nbr;
|
return nbr;
|
||||||
|
|
||||||
|
TRACE(D_EVENTS, "New neighbor %I on %s", addr, ifa->iface->name);
|
||||||
|
|
||||||
nbr = mb_allocz(ifa->pool, sizeof(struct babel_neighbor));
|
nbr = mb_allocz(ifa->pool, sizeof(struct babel_neighbor));
|
||||||
nbr->ifa = ifa;
|
nbr->ifa = ifa;
|
||||||
nbr->addr = addr;
|
nbr->addr = addr;
|
||||||
|
nbr->rxcost = BABEL_INFINITY;
|
||||||
nbr->txcost = BABEL_INFINITY;
|
nbr->txcost = BABEL_INFINITY;
|
||||||
|
nbr->cost = BABEL_INFINITY;
|
||||||
init_list(&nbr->routes);
|
init_list(&nbr->routes);
|
||||||
add_tail(&ifa->neigh_list, NODE nbr);
|
add_tail(&ifa->neigh_list, NODE nbr);
|
||||||
|
|
||||||
|
@ -316,12 +322,11 @@ babel_get_neighbor(struct babel_iface *ifa, ip_addr addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
babel_flush_neighbor(struct babel_neighbor *nbr)
|
babel_flush_neighbor(struct babel_proto *p, struct babel_neighbor *nbr)
|
||||||
{
|
{
|
||||||
struct babel_proto *p = nbr->ifa->proto;
|
|
||||||
node *n;
|
node *n;
|
||||||
|
|
||||||
TRACE(D_EVENTS, "Flushing neighbor %I", nbr->addr);
|
TRACE(D_EVENTS, "Removing neighbor %I on %s", nbr->addr, nbr->ifa->iface->name);
|
||||||
|
|
||||||
WALK_LIST_FIRST(n, nbr->routes)
|
WALK_LIST_FIRST(n, nbr->routes)
|
||||||
{
|
{
|
||||||
|
@ -340,24 +345,33 @@ babel_flush_neighbor(struct babel_neighbor *nbr)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
babel_expire_ihu(struct babel_neighbor *nbr)
|
babel_expire_ihu(struct babel_proto *p, struct babel_neighbor *nbr)
|
||||||
{
|
{
|
||||||
|
TRACE(D_EVENTS, "IHU from nbr %I on %s expired", nbr->addr, nbr->ifa->iface->name);
|
||||||
|
|
||||||
nbr->txcost = BABEL_INFINITY;
|
nbr->txcost = BABEL_INFINITY;
|
||||||
nbr->ihu_expiry = 0;
|
nbr->ihu_expiry = 0;
|
||||||
|
babel_update_cost(nbr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
babel_expire_hello(struct babel_neighbor *nbr)
|
babel_expire_hello(struct babel_proto *p, struct babel_neighbor *nbr)
|
||||||
{
|
{
|
||||||
nbr->hello_map <<= 1;
|
nbr->hello_map <<= 1;
|
||||||
|
|
||||||
if (nbr->hello_cnt < 16)
|
if (nbr->hello_cnt < 16)
|
||||||
nbr->hello_cnt++;
|
nbr->hello_cnt++;
|
||||||
|
|
||||||
|
TRACE(D_EVENTS, "Hello from nbr %I on %s expired, %d left",
|
||||||
|
nbr->addr, nbr->ifa->iface->name, u32_popcount(nbr->hello_map));
|
||||||
|
|
||||||
if (nbr->hello_map)
|
if (nbr->hello_map)
|
||||||
|
{
|
||||||
nbr->hello_expiry += nbr->last_hello_int;
|
nbr->hello_expiry += nbr->last_hello_int;
|
||||||
|
babel_update_cost(nbr);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
babel_flush_neighbor(nbr);
|
babel_flush_neighbor(p, nbr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -372,10 +386,10 @@ babel_expire_neighbors(struct babel_proto *p)
|
||||||
WALK_LIST_DELSAFE(nbr, nbx, ifa->neigh_list)
|
WALK_LIST_DELSAFE(nbr, nbx, ifa->neigh_list)
|
||||||
{
|
{
|
||||||
if (nbr->ihu_expiry && nbr->ihu_expiry <= now_)
|
if (nbr->ihu_expiry && nbr->ihu_expiry <= now_)
|
||||||
babel_expire_ihu(nbr);
|
babel_expire_ihu(p, nbr);
|
||||||
|
|
||||||
if (nbr->hello_expiry && nbr->hello_expiry <= now_)
|
if (nbr->hello_expiry && nbr->hello_expiry <= now_)
|
||||||
babel_expire_hello(nbr);
|
babel_expire_hello(p, nbr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -409,66 +423,81 @@ babel_is_feasible(struct babel_source *s, u16 seqno, u16 metric)
|
||||||
((seqno == s->seqno) && (metric < s->metric));
|
((seqno == s->seqno) && (metric < s->metric));
|
||||||
}
|
}
|
||||||
|
|
||||||
static u16
|
|
||||||
babel_compute_rxcost(struct babel_neighbor *n)
|
|
||||||
{
|
|
||||||
struct babel_iface *ifa = n->ifa;
|
|
||||||
u8 cnt, missed;
|
|
||||||
u16 map=n->hello_map;
|
|
||||||
|
|
||||||
if (!map) return BABEL_INFINITY;
|
|
||||||
cnt = u32_popcount(map); // number of bits set
|
|
||||||
missed = n->hello_cnt-cnt;
|
|
||||||
|
|
||||||
if (ifa->cf->type == BABEL_IFACE_TYPE_WIRELESS)
|
|
||||||
{
|
|
||||||
/* ETX - Appendix 2.2 in the RFC.
|
|
||||||
|
|
||||||
beta = prob. of successful transmission.
|
|
||||||
rxcost = BABEL_RXCOST_WIRELESS/beta
|
|
||||||
|
|
||||||
Since: beta = 1-missed/n->hello_cnt = cnt/n->hello_cnt
|
|
||||||
Then: rxcost = BABEL_RXCOST_WIRELESS * n->hello_cnt / cnt
|
|
||||||
*/
|
|
||||||
if (!cnt) return BABEL_INFINITY;
|
|
||||||
return BABEL_RXCOST_WIRELESS * n->hello_cnt / cnt;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* k-out-of-j selection - Appendix 2.1 in the RFC. */
|
|
||||||
DBG("Babel: Missed %d hellos from %I\n", missed, n->addr);
|
|
||||||
/* Link is bad if more than half the expected hellos were lost */
|
|
||||||
return (missed > n->hello_cnt/2) ? BABEL_INFINITY : ifa->cf->rxcost;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static u16
|
|
||||||
babel_compute_cost(struct babel_neighbor *n)
|
|
||||||
{
|
|
||||||
struct babel_iface *ifa = n->ifa;
|
|
||||||
u16 rxcost = babel_compute_rxcost(n);
|
|
||||||
if (rxcost == BABEL_INFINITY) return rxcost;
|
|
||||||
else if (ifa->cf->type == BABEL_IFACE_TYPE_WIRELESS)
|
|
||||||
{
|
|
||||||
/* ETX - Appendix 2.2 in the RFC */
|
|
||||||
return (MAX(n->txcost, BABEL_RXCOST_WIRELESS) * rxcost)/BABEL_RXCOST_WIRELESS;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* k-out-of-j selection - Appendix 2.1 in the RFC. */
|
|
||||||
return n->txcost;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Simple additive metric - Appendix 3.1 in the RFC */
|
/* Simple additive metric - Appendix 3.1 in the RFC */
|
||||||
static u16
|
static inline u16
|
||||||
babel_compute_metric(struct babel_neighbor *n, uint metric)
|
babel_compute_metric(struct babel_neighbor *n, uint metric)
|
||||||
{
|
{
|
||||||
metric += babel_compute_cost(n);
|
return MIN(metric + n->cost, BABEL_INFINITY);
|
||||||
return MIN(metric, BABEL_INFINITY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
babel_update_cost(struct babel_neighbor *nbr)
|
||||||
|
{
|
||||||
|
struct babel_proto *p = nbr->ifa->proto;
|
||||||
|
struct babel_iface_config *cf = nbr->ifa->cf;
|
||||||
|
uint rcv = u32_popcount(nbr->hello_map); // number of bits set
|
||||||
|
uint max = nbr->hello_cnt;
|
||||||
|
uint rxcost = BABEL_INFINITY; /* Cost to announce in IHU */
|
||||||
|
uint txcost = BABEL_INFINITY; /* Effective cost for route selection */
|
||||||
|
|
||||||
|
if (!rcv || !nbr->ifa->up)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
switch (cf->type)
|
||||||
|
{
|
||||||
|
case BABEL_IFACE_TYPE_WIRED:
|
||||||
|
/* 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 */
|
||||||
|
if (rcv * 16 < cf->limit * max)
|
||||||
|
break;
|
||||||
|
|
||||||
|
rxcost = cf->rxcost;
|
||||||
|
txcost = nbr->txcost;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BABEL_IFACE_TYPE_WIRELESS:
|
||||||
|
/*
|
||||||
|
* ETX - Appendix 2.2 in the RFC.
|
||||||
|
*
|
||||||
|
* alpha = prob. of successful transmission estimated by the neighbor
|
||||||
|
* beta = prob. of successful transmission estimated by the router
|
||||||
|
* rxcost = nominal rxcost of the router / beta
|
||||||
|
* txcost = nominal rxcost of the neighbor / (alpha * beta)
|
||||||
|
* = received txcost / beta
|
||||||
|
*
|
||||||
|
* Note that received txcost is just neighbor's rxcost. Beta is rcv/max,
|
||||||
|
* we use inverse values of beta (i.e. max/rcv) to stay in integers.
|
||||||
|
*/
|
||||||
|
rxcost = MIN( cf->rxcost * max / rcv, BABEL_INFINITY);
|
||||||
|
txcost = MIN(nbr->txcost * max / rcv, BABEL_INFINITY);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
/* If RX cost changed, send IHU with next Hello */
|
||||||
|
if (rxcost != nbr->rxcost)
|
||||||
|
{
|
||||||
|
nbr->rxcost = rxcost;
|
||||||
|
nbr->ihu_cnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If link cost changed, run route selection */
|
||||||
|
if (txcost != nbr->cost)
|
||||||
|
{
|
||||||
|
TRACE(D_EVENTS, "Cost of nbr %I on %s changed from %u to %u",
|
||||||
|
nbr->addr, nbr->ifa->iface->name, nbr->cost, txcost);
|
||||||
|
|
||||||
|
nbr->cost = txcost;
|
||||||
|
|
||||||
|
struct babel_route *r; node *n;
|
||||||
|
WALK_LIST2(r, n, nbr->routes, neigh_route)
|
||||||
|
{
|
||||||
|
r->metric = babel_compute_metric(nbr, r->advert_metric);
|
||||||
|
babel_select_route(r->e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* babel_announce_rte - announce selected route to the core
|
* babel_announce_rte - announce selected route to the core
|
||||||
|
@ -506,6 +535,7 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
|
||||||
rte->u.babel.router_id = r->router_id;
|
rte->u.babel.router_id = r->router_id;
|
||||||
rte->pflags = 0;
|
rte->pflags = 0;
|
||||||
|
|
||||||
|
r->old_metric = r->metric;
|
||||||
rte_update2(c, e->n.addr, rte, p->p.main_source);
|
rte_update2(c, e->n.addr, rte, p->p.main_source);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -535,7 +565,7 @@ static void
|
||||||
babel_select_route(struct babel_entry *e)
|
babel_select_route(struct babel_entry *e)
|
||||||
{
|
{
|
||||||
struct babel_proto *p = e->proto;
|
struct babel_proto *p = e->proto;
|
||||||
struct babel_route *r, *cur = e->selected_in;
|
struct babel_route *r, *cur = e->selected_in, *best = e->selected_in;
|
||||||
|
|
||||||
/* try to find the best feasible route */
|
/* try to find the best feasible route */
|
||||||
WALK_LIST(r, e->routes)
|
WALK_LIST(r, e->routes)
|
||||||
|
@ -544,10 +574,10 @@ babel_select_route(struct babel_entry *e)
|
||||||
babel_is_feasible(babel_find_source(e, r->router_id), r->seqno, r->advert_metric))
|
babel_is_feasible(babel_find_source(e, r->router_id), r->seqno, r->advert_metric))
|
||||||
cur = r;
|
cur = r;
|
||||||
|
|
||||||
if (cur && !OUR_ROUTE(cur) &&
|
if (cur && !OUR_ROUTE(cur) && (cur->metric < BABEL_INFINITY) &&
|
||||||
((!e->selected_in && cur->metric < BABEL_INFINITY) ||
|
(!best || (cur->metric < best->metric) || ((cur == best) && (cur->metric != cur->old_metric))))
|
||||||
(e->selected_in && cur->metric < e->selected_in->metric)))
|
|
||||||
{
|
{
|
||||||
|
if (cur != best)
|
||||||
TRACE(D_EVENTS, "Picked new route for prefix %N: router id %lR metric %d",
|
TRACE(D_EVENTS, "Picked new route for prefix %N: router id %lR metric %d",
|
||||||
e->n.addr, cur->router_id, cur->metric);
|
e->n.addr, cur->router_id, cur->metric);
|
||||||
|
|
||||||
|
@ -564,10 +594,9 @@ babel_select_route(struct babel_entry *e)
|
||||||
babel_build_rte() will set the unreachable flag if the metric is BABEL_INFINITY.*/
|
babel_build_rte() will set the unreachable flag if the metric is BABEL_INFINITY.*/
|
||||||
if (e->selected_in)
|
if (e->selected_in)
|
||||||
{
|
{
|
||||||
TRACE(D_EVENTS, "Lost feasible route for prefix %N",
|
TRACE(D_EVENTS, "Lost feasible route for prefix %N", e->n.addr);
|
||||||
e->n.addr);
|
|
||||||
|
|
||||||
e->selected_in->metric = BABEL_INFINITY;
|
e->selected_in->metric = e->selected_in->advert_metric = BABEL_INFINITY;
|
||||||
e->updated = current_time();
|
e->updated = current_time();
|
||||||
|
|
||||||
babel_send_seqno_request(e);
|
babel_send_seqno_request(e);
|
||||||
|
@ -583,7 +612,7 @@ babel_select_route(struct babel_entry *e)
|
||||||
/* No route currently selected, and no new one selected; this means we
|
/* No route currently selected, and no new one selected; this means we
|
||||||
don't have a route to this destination anymore (and were probably
|
don't have a route to this destination anymore (and were probably
|
||||||
called from an expiry timer). Remove the route from the nest. */
|
called from an expiry timer). Remove the route from the nest. */
|
||||||
TRACE(D_EVENTS, "Flushing route for prefix %N", e->n.addr);
|
// TRACE(D_EVENTS, "Flushing route for prefix %N", e->n.addr);
|
||||||
|
|
||||||
e->selected_in = NULL;
|
e->selected_in = NULL;
|
||||||
e->updated = current_time();
|
e->updated = current_time();
|
||||||
|
@ -617,7 +646,7 @@ babel_build_ihu(union babel_msg *msg, struct babel_iface *ifa, struct babel_neig
|
||||||
|
|
||||||
msg->type = BABEL_TLV_IHU;
|
msg->type = BABEL_TLV_IHU;
|
||||||
msg->ihu.addr = n->addr;
|
msg->ihu.addr = n->addr;
|
||||||
msg->ihu.rxcost = babel_compute_rxcost(n);
|
msg->ihu.rxcost = n->rxcost;
|
||||||
msg->ihu.interval = ifa->cf->ihu_interval;
|
msg->ihu.interval = ifa->cf->ihu_interval;
|
||||||
|
|
||||||
TRACE(D_PACKETS, "Sending IHU for %I with rxcost %d interval %t",
|
TRACE(D_PACKETS, "Sending IHU for %I with rxcost %d interval %t",
|
||||||
|
@ -630,6 +659,7 @@ babel_send_ihu(struct babel_iface *ifa, struct babel_neighbor *n)
|
||||||
union babel_msg msg = {};
|
union babel_msg msg = {};
|
||||||
babel_build_ihu(&msg, ifa, n);
|
babel_build_ihu(&msg, ifa, n);
|
||||||
babel_send_unicast(&msg, ifa, n->addr);
|
babel_send_unicast(&msg, ifa, n->addr);
|
||||||
|
n->ihu_cnt = BABEL_IHU_INTERVAL_FACTOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -637,15 +667,19 @@ babel_send_ihus(struct babel_iface *ifa)
|
||||||
{
|
{
|
||||||
struct babel_neighbor *n;
|
struct babel_neighbor *n;
|
||||||
WALK_LIST(n, ifa->neigh_list)
|
WALK_LIST(n, ifa->neigh_list)
|
||||||
|
{
|
||||||
|
if (n->hello_cnt && (--n->ihu_cnt <= 0))
|
||||||
{
|
{
|
||||||
union babel_msg msg = {};
|
union babel_msg msg = {};
|
||||||
babel_build_ihu(&msg, ifa, n);
|
babel_build_ihu(&msg, ifa, n);
|
||||||
babel_enqueue(&msg, ifa);
|
babel_enqueue(&msg, ifa);
|
||||||
|
n->ihu_cnt = BABEL_IHU_INTERVAL_FACTOR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
babel_send_hello(struct babel_iface *ifa, u8 send_ihu)
|
babel_send_hello(struct babel_iface *ifa)
|
||||||
{
|
{
|
||||||
struct babel_proto *p = ifa->proto;
|
struct babel_proto *p = ifa->proto;
|
||||||
union babel_msg msg = {};
|
union babel_msg msg = {};
|
||||||
|
@ -659,7 +693,6 @@ babel_send_hello(struct babel_iface *ifa, u8 send_ihu)
|
||||||
|
|
||||||
babel_enqueue(&msg, ifa);
|
babel_enqueue(&msg, ifa);
|
||||||
|
|
||||||
if (send_ihu)
|
|
||||||
babel_send_ihus(ifa);
|
babel_send_ihus(ifa);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -907,7 +940,7 @@ babel_update_hello_history(struct babel_neighbor *n, u16 seqno, uint interval)
|
||||||
|
|
||||||
u16 delta = ((uint) seqno - (uint) n->next_hello_seqno);
|
u16 delta = ((uint) seqno - (uint) n->next_hello_seqno);
|
||||||
|
|
||||||
if (delta == 0)
|
if ((delta == 0) || (n->hello_cnt == 0))
|
||||||
{
|
{
|
||||||
/* Do nothing */
|
/* Do nothing */
|
||||||
}
|
}
|
||||||
|
@ -934,6 +967,8 @@ babel_update_hello_history(struct babel_neighbor *n, u16 seqno, uint interval)
|
||||||
n->hello_map = (n->hello_map << 1) | 1;
|
n->hello_map = (n->hello_map << 1) | 1;
|
||||||
n->next_hello_seqno = seqno+1;
|
n->next_hello_seqno = seqno+1;
|
||||||
if (n->hello_cnt < 16) n->hello_cnt++;
|
if (n->hello_cnt < 16) n->hello_cnt++;
|
||||||
|
|
||||||
|
/* Update expiration */
|
||||||
n->hello_expiry = current_time() + BABEL_HELLO_EXPIRY_FACTOR(interval);
|
n->hello_expiry = current_time() + BABEL_HELLO_EXPIRY_FACTOR(interval);
|
||||||
n->last_hello_int = interval;
|
n->last_hello_int = interval;
|
||||||
}
|
}
|
||||||
|
@ -1041,8 +1076,13 @@ 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);
|
||||||
|
int first_hello = !n->hello_cnt;
|
||||||
|
|
||||||
babel_update_hello_history(n, msg->seqno, msg->interval);
|
babel_update_hello_history(n, msg->seqno, msg->interval);
|
||||||
if (ifa->cf->type == BABEL_IFACE_TYPE_WIRELESS)
|
babel_update_cost(n);
|
||||||
|
|
||||||
|
/* Speed up session establishment by sending IHU immediately */
|
||||||
|
if (first_hello)
|
||||||
babel_send_ihu(ifa, n);
|
babel_send_ihu(ifa, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1062,6 +1102,7 @@ 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);
|
||||||
|
babel_update_cost(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1159,7 +1200,7 @@ babel_handle_update(union babel_msg *m, struct babel_iface *ifa)
|
||||||
WALK_LIST(n, nbr->routes)
|
WALK_LIST(n, nbr->routes)
|
||||||
{
|
{
|
||||||
r = SKIP_BACK(struct babel_route, neigh_route, n);
|
r = SKIP_BACK(struct babel_route, neigh_route, n);
|
||||||
r->metric = BABEL_INFINITY;
|
r->metric = r->advert_metric = BABEL_INFINITY;
|
||||||
babel_select_route(r->e);
|
babel_select_route(r->e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1176,7 +1217,7 @@ babel_handle_update(union babel_msg *m, struct babel_iface *ifa)
|
||||||
if (!r)
|
if (!r)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
r->metric = BABEL_INFINITY;
|
r->metric = r->advert_metric = BABEL_INFINITY;
|
||||||
babel_select_route(e);
|
babel_select_route(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1215,7 +1256,7 @@ babel_handle_update(union babel_msg *m, struct babel_iface *ifa)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Treat as retraction */
|
/* Treat as retraction */
|
||||||
r->metric = BABEL_INFINITY;
|
r->metric = r->advert_metric = BABEL_INFINITY;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1347,8 +1388,7 @@ babel_iface_timer(timer *t)
|
||||||
|
|
||||||
if (now_ >= ifa->next_hello)
|
if (now_ >= ifa->next_hello)
|
||||||
{
|
{
|
||||||
babel_send_hello(ifa, (ifa->cf->type == BABEL_IFACE_TYPE_WIRELESS ||
|
babel_send_hello(ifa);
|
||||||
ifa->hello_seqno % BABEL_IHU_INTERVAL_FACTOR == 0));
|
|
||||||
ifa->next_hello += hello_period * (1 + (now_ - ifa->next_hello) / hello_period);
|
ifa->next_hello += hello_period * (1 + (now_ - ifa->next_hello) / hello_period);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1395,7 +1435,7 @@ babel_iface_start(struct babel_iface *ifa)
|
||||||
tm2_start(ifa->timer, 100 MS);
|
tm2_start(ifa->timer, 100 MS);
|
||||||
ifa->up = 1;
|
ifa->up = 1;
|
||||||
|
|
||||||
babel_send_hello(ifa, 0);
|
babel_send_hello(ifa);
|
||||||
babel_send_wildcard_retraction(ifa);
|
babel_send_wildcard_retraction(ifa);
|
||||||
babel_send_wildcard_request(ifa);
|
babel_send_wildcard_request(ifa);
|
||||||
babel_send_update(ifa, 0); /* Full update */
|
babel_send_update(ifa, 0); /* Full update */
|
||||||
|
@ -1422,8 +1462,10 @@ babel_iface_stop(struct babel_iface *ifa)
|
||||||
WALK_LIST(n, nbr->routes)
|
WALK_LIST(n, nbr->routes)
|
||||||
{
|
{
|
||||||
r = SKIP_BACK(struct babel_route, neigh_route, n);
|
r = SKIP_BACK(struct babel_route, neigh_route, n);
|
||||||
r->metric = BABEL_INFINITY;
|
r->metric = r->advert_metric = BABEL_INFINITY;
|
||||||
r->expires = now_ + r->expiry_interval;
|
r->expires = now_ + r->expiry_interval;
|
||||||
|
|
||||||
|
if (r == r->e->selected_in)
|
||||||
babel_select_route(r->e);
|
babel_select_route(r->e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1551,7 +1593,7 @@ babel_remove_iface(struct babel_proto *p, struct babel_iface *ifa)
|
||||||
|
|
||||||
struct babel_neighbor *n;
|
struct babel_neighbor *n;
|
||||||
WALK_LIST_FIRST(n, ifa->neigh_list)
|
WALK_LIST_FIRST(n, ifa->neigh_list)
|
||||||
babel_flush_neighbor(n);
|
babel_flush_neighbor(p, n);
|
||||||
|
|
||||||
rem_node(NODE ifa);
|
rem_node(NODE ifa);
|
||||||
|
|
||||||
|
@ -1871,7 +1913,7 @@ babel_show_neighbors(struct proto *P, char *iff)
|
||||||
uint hellos = u32_popcount(n->hello_map);
|
uint hellos = u32_popcount(n->hello_map);
|
||||||
btime timer = n->hello_expiry - current_time();
|
btime timer = n->hello_expiry - current_time();
|
||||||
cli_msg(-1024, "%-25I %-10s %6u %6u %6u %7t",
|
cli_msg(-1024, "%-25I %-10s %6u %6u %6u %7t",
|
||||||
n->addr, ifa->iface->name, n->txcost, rts, hellos, MAX(timer, 0));
|
n->addr, ifa->iface->name, n->cost, rts, hellos, MAX(timer, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,9 +34,10 @@
|
||||||
|
|
||||||
#define BABEL_HELLO_INTERVAL_WIRED (4 S_) /* Default hello intervals in seconds */
|
#define BABEL_HELLO_INTERVAL_WIRED (4 S_) /* Default hello intervals in seconds */
|
||||||
#define BABEL_HELLO_INTERVAL_WIRELESS (4 S_)
|
#define BABEL_HELLO_INTERVAL_WIRELESS (4 S_)
|
||||||
|
#define BABEL_HELLO_LIMIT 12
|
||||||
#define BABEL_UPDATE_INTERVAL_FACTOR 4
|
#define BABEL_UPDATE_INTERVAL_FACTOR 4
|
||||||
#define BABEL_IHU_INTERVAL_FACTOR 3
|
#define BABEL_IHU_INTERVAL_FACTOR 3
|
||||||
#define BABEL_IHU_EXPIRY_FACTOR(X) ((btime)(X)*3/2) /* 1.5 */
|
#define BABEL_IHU_EXPIRY_FACTOR(X) ((btime)(X)*7/2) /* 3.5 */
|
||||||
#define BABEL_HELLO_EXPIRY_FACTOR(X) ((btime)(X)*3/2) /* 1.5 */
|
#define BABEL_HELLO_EXPIRY_FACTOR(X) ((btime)(X)*3/2) /* 1.5 */
|
||||||
#define BABEL_ROUTE_EXPIRY_FACTOR(X) ((btime)(X)*7/2) /* 3.5 */
|
#define BABEL_ROUTE_EXPIRY_FACTOR(X) ((btime)(X)*7/2) /* 3.5 */
|
||||||
#define BABEL_ROUTE_REFRESH_INTERVAL (2 S_) /* Time before route expiry to send route request */
|
#define BABEL_ROUTE_REFRESH_INTERVAL (2 S_) /* Time before route expiry to send route request */
|
||||||
|
@ -112,6 +113,7 @@ struct babel_iface_config {
|
||||||
|
|
||||||
u16 rxcost;
|
u16 rxcost;
|
||||||
u8 type;
|
u8 type;
|
||||||
|
u8 limit; /* Minimum number of Hellos to keep link up */
|
||||||
u8 check_link;
|
u8 check_link;
|
||||||
uint port;
|
uint port;
|
||||||
uint hello_interval; /* Hello interval, in us */
|
uint hello_interval; /* Hello interval, in us */
|
||||||
|
@ -188,7 +190,10 @@ struct babel_neighbor {
|
||||||
struct babel_iface *ifa;
|
struct babel_iface *ifa;
|
||||||
|
|
||||||
ip_addr addr;
|
ip_addr addr;
|
||||||
u16 txcost;
|
u16 rxcost; /* Sent in last IHU */
|
||||||
|
u16 txcost; /* Received in last IHU */
|
||||||
|
u16 cost; /* Computed neighbor cost */
|
||||||
|
s8 ihu_cnt; /* IHU countdown, 0 to send it */
|
||||||
u8 hello_cnt;
|
u8 hello_cnt;
|
||||||
u16 hello_map;
|
u16 hello_map;
|
||||||
u16 next_hello_seqno;
|
u16 next_hello_seqno;
|
||||||
|
@ -218,6 +223,7 @@ struct babel_route {
|
||||||
u16 seqno;
|
u16 seqno;
|
||||||
u16 advert_metric;
|
u16 advert_metric;
|
||||||
u16 metric;
|
u16 metric;
|
||||||
|
u16 old_metric;
|
||||||
u64 router_id;
|
u64 router_id;
|
||||||
ip_addr next_hop;
|
ip_addr next_hop;
|
||||||
btime refresh_time;
|
btime refresh_time;
|
||||||
|
|
|
@ -56,6 +56,7 @@ babel_iface_start:
|
||||||
init_list(&this_ipatt->ipn_list);
|
init_list(&this_ipatt->ipn_list);
|
||||||
BABEL_IFACE->port = BABEL_PORT;
|
BABEL_IFACE->port = BABEL_PORT;
|
||||||
BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRED;
|
BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRED;
|
||||||
|
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->check_link = 1;
|
BABEL_IFACE->check_link = 1;
|
||||||
|
@ -89,6 +90,7 @@ babel_iface_finish:
|
||||||
babel_iface_item:
|
babel_iface_item:
|
||||||
| PORT expr { BABEL_IFACE->port = $2; if (($2<1) || ($2>65535)) cf_error("Invalid port number"); }
|
| PORT expr { BABEL_IFACE->port = $2; if (($2<1) || ($2>65535)) cf_error("Invalid port number"); }
|
||||||
| RXCOST expr { BABEL_IFACE->rxcost = $2; if (($2<1) || ($2>65535)) cf_error("Invalid rxcost"); }
|
| RXCOST expr { BABEL_IFACE->rxcost = $2; if (($2<1) || ($2>65535)) cf_error("Invalid rxcost"); }
|
||||||
|
| 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; }
|
||||||
| 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"); }
|
||||||
|
|
Loading…
Reference in a new issue