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:
Ondrej Zajicek (work) 2017-10-25 17:14:08 +02:00
parent f00221fadb
commit b47eaefe12
4 changed files with 170 additions and 108 deletions

View file

@ -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>

View file

@ -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));
} }
} }

View file

@ -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;

View file

@ -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"); }