RPL probing: now using link-stats to first prioritize probing of non-fresh parents, and to support urgent probing (fast probing of a potential new preferred parent

This commit is contained in:
Simon Duquennoy 2015-11-29 21:46:41 +01:00 committed by Simon Duquennoy
parent 426e10c3ed
commit c5cf8608e9
4 changed files with 64 additions and 31 deletions

View file

@ -291,7 +291,7 @@
#ifdef RPL_CONF_PROBING_SELECT_FUNC
#define RPL_PROBING_SELECT_FUNC RPL_CONF_PROBING_SELECT_FUNC
#else
#define RPL_PROBING_SELECT_FUNC(dag) get_probing_target((dag))
#define RPL_PROBING_SELECT_FUNC get_probing_target
#endif
/*
@ -314,8 +314,7 @@
#ifdef RPL_CONF_PROBING_DELAY_FUNC
#define RPL_PROBING_DELAY_FUNC RPL_CONF_PROBING_DELAY_FUNC
#else
#define RPL_PROBING_DELAY_FUNC() ((RPL_PROBING_INTERVAL / 2) \
+ random_rand() % (RPL_PROBING_INTERVAL))
#define RPL_PROBING_DELAY_FUNC get_probing_delay
#endif
/*

View file

@ -96,12 +96,13 @@ rpl_print_neighbor_list(void)
int curr_dio_interval = default_instance->dio_intcurrent;
int curr_rank = default_instance->current_dag->rank;
rpl_parent_t *p = nbr_table_head(rpl_parents);
const struct link_stats *stats = rpl_get_parent_link_stats(p);
clock_time_t clock_now = clock_time();
printf("RPL: OCP %u rank %u dioint %u, nbr count %u\n",
default_instance->of->ocp, curr_rank, curr_dio_interval, uip_ds6_nbr_num());
while(p != NULL) {
printf("RPL: nbr %3u %5u, %5u => %5u -- %5u %c%c (last tx %u min ago)\n",
const struct link_stats *stats = rpl_get_parent_link_stats(p);
printf("RPL: nbr %3u %5u, %5u => %5u -- %2u %c%c (last tx %u min ago)\n",
rpl_get_parent_ipaddr(p)->u8[15],
p->rank,
rpl_get_parent_link_metric(p),
@ -109,7 +110,7 @@ rpl_print_neighbor_list(void)
stats != NULL ? stats->freshness : 0,
link_stats_is_fresh(stats) ? 'f' : ' ',
p == default_instance->current_dag->preferred_parent ? 'p' : ' ',
(unsigned)((now - p->last_tx_time) / (60 * CLOCK_SECOND))
(unsigned)((clock_now - stats->last_tx_time) / (60 * CLOCK_SECOND))
);
p = nbr_table_next(rpl_parents, p);
}
@ -868,6 +869,10 @@ rpl_select_parent(rpl_dag_t *dag)
if(rpl_parent_is_fresh(best)) {
rpl_set_preferred_parent(dag, best);
dag->rank = rpl_rank_via_parent(dag->preferred_parent);
} else {
/* Probe the new best parent shortly in order to get a fresh estimate */
dag->instance->urgent_probing_target = best;
rpl_schedule_probing(dag->instance);
}
} else {
rpl_set_preferred_parent(dag, best);

View file

@ -56,6 +56,14 @@
void RPL_CALLBACK_NEW_DIO_INTERVAL(uint8_t dio_interval);
#endif /* RPL_CALLBACK_NEW_DIO_INTERVAL */
#ifdef RPL_PROBING_SELECT_FUNC
rpl_parent_t *RPL_PROBING_SELECT_FUNC(rpl_dag_t *dag);
#endif /* RPL_PROBING_SELECT_FUNC */
#ifdef RPL_PROBING_DELAY_FUNC
clock_time_t RPL_PROBING_DELAY_FUNC(rpl_dag_t *dag);
#endif /* RPL_PROBING_DELAY_FUNC */
/*---------------------------------------------------------------------------*/
static struct ctimer periodic_timer;
@ -359,42 +367,57 @@ rpl_schedule_unicast_dio_immediately(rpl_instance_t *instance)
}
/*---------------------------------------------------------------------------*/
#if RPL_WITH_PROBING
static rpl_parent_t *
clock_time_t
get_probing_delay(rpl_dag_t *dag)
{
if(dag != NULL && dag->instance != NULL
&& dag->instance->urgent_probing_target != NULL) {
/* Urgent probing needed (to find out if a neighbor may become preferred parent) */
return random_rand() % (CLOCK_SECOND * 10);
} else {
/* Else, use normal probing interval */
return ((RPL_PROBING_INTERVAL) / 2) + random_rand() % (RPL_PROBING_INTERVAL);
}
}
/*---------------------------------------------------------------------------*/
rpl_parent_t *
get_probing_target(rpl_dag_t *dag)
{
/* Returns the next probing target. The current implementation probes the current
* preferred parent if we have not updated its link for RPL_PROBING_EXPIRATION_TIME.
/* Returns the next probing target. The current implementation probes the urgent
* probing target if any, or the preferred parent if its link statistics need refresh.
* Otherwise, it picks at random between:
* (1) selecting the best parent not updated for RPL_PROBING_EXPIRATION_TIME
* (1) selecting the best parent with non-fresh link statistics
* (2) selecting the least recently updated parent
*/
rpl_parent_t *p;
rpl_parent_t *probing_target = NULL;
rpl_rank_t probing_target_rank = INFINITE_RANK;
/* min_last_tx is the clock time RPL_PROBING_EXPIRATION_TIME in the past */
clock_time_t min_last_tx = clock_time();
min_last_tx = min_last_tx > 2 * RPL_PROBING_EXPIRATION_TIME
? min_last_tx - RPL_PROBING_EXPIRATION_TIME : 1;
clock_time_t probing_target_age = 0;
clock_time_t clock_now = clock_time();
if(dag == NULL ||
dag->instance == NULL ||
dag->preferred_parent == NULL) {
dag->instance == NULL) {
return NULL;
}
/* Our preferred parent needs probing */
if(dag->preferred_parent->last_tx_time < min_last_tx) {
probing_target = dag->preferred_parent;
/* There is an urgent probing target */
if(dag->instance->urgent_probing_target != NULL) {
return dag->instance->urgent_probing_target;
}
/* With 50% probability: probe best parent not updated for RPL_PROBING_EXPIRATION_TIME */
if(probing_target == NULL && (random_rand() % 2) == 0) {
/* The preferred parent needs probing */
if(dag->preferred_parent != NULL && !rpl_parent_is_fresh(dag->preferred_parent)) {
return dag->preferred_parent;
}
/* With 50% probability: probe best non-fresh parent */
if(random_rand() % 2 == 0) {
p = nbr_table_head(rpl_parents);
while(p != NULL) {
if(p->dag == dag && p->last_tx_time < min_last_tx) {
if(p->dag == dag && !rpl_parent_is_fresh(p)) {
/* p is in our dag and needs probing */
rpl_rank_t p_rank = dag->instance->of->calculate_rank(p, 0);
rpl_rank_t p_rank = rpl_rank_via_parent(p);
if(probing_target == NULL
|| p_rank < probing_target_rank) {
probing_target = p;
@ -405,14 +428,16 @@ get_probing_target(rpl_dag_t *dag)
}
}
/* The default probing target is the least recently updated parent */
/* If we still do not have a probing target: pick the least recently updated parent */
if(probing_target == NULL) {
p = nbr_table_head(rpl_parents);
while(p != NULL) {
if(p->dag == dag) {
const struct link_stats *stats =rpl_get_parent_link_stats(p);
if(p->dag == dag && stats != NULL) {
if(probing_target == NULL
|| p->last_tx_time < probing_target->last_tx_time) {
|| clock_now - stats->last_tx_time > probing_target_age) {
probing_target = p;
probing_target_age = clock_now - stats->last_tx_time;
}
}
p = nbr_table_next(rpl_parents, p);
@ -431,11 +456,14 @@ handle_probing_timer(void *ptr)
/* Perform probing */
if(target_ipaddr != NULL) {
PRINTF("RPL: probing %u ((last tx %u min ago))\n",
nbr_table_get_lladdr(rpl_parents, probing_target)->u8[7],
(unsigned)((clock_time() - probing_target->last_tx_time) / (60 * CLOCK_SECOND)));
/* Send probe (unicast DIO or DIS) */
PRINTF("RPL: probing %u %s last tx %u min ago\n",
rpl_get_parent_llpaddr(probing_target)->u8[7],
instance->urgent_probing_target != NULL ? "(urgent)" : "",
(unsigned)((clock_time() - probing_target->last_tx_time) / (60 * CLOCK_SECOND)),
);
/* Send probe, e.g. unicast DIO or DIS */
RPL_PROBING_SEND_FUNC(instance, target_ipaddr);
instance->urgent_probing_target = NULL;
}
/* Schedule next probing */
@ -449,7 +477,7 @@ handle_probing_timer(void *ptr)
void
rpl_schedule_probing(rpl_instance_t *instance)
{
ctimer_set(&instance->probing_timer, RPL_PROBING_DELAY_FUNC(),
ctimer_set(&instance->probing_timer, RPL_PROBING_DELAY_FUNC(instance->current_dag),
handle_probing_timer, instance);
}
#endif /* RPL_WITH_PROBING */

View file

@ -246,6 +246,7 @@ struct rpl_instance {
clock_time_t dio_next_delay; /* delay for completion of dio interval */
#if RPL_WITH_PROBING
struct ctimer probing_timer;
rpl_parent_t *urgent_probing_target;
#endif /* RPL_WITH_PROBING */
struct ctimer dio_timer;
struct ctimer dao_timer;