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

View file

@ -96,12 +96,13 @@ rpl_print_neighbor_list(void)
int curr_dio_interval = default_instance->dio_intcurrent; int curr_dio_interval = default_instance->dio_intcurrent;
int curr_rank = default_instance->current_dag->rank; int curr_rank = default_instance->current_dag->rank;
rpl_parent_t *p = nbr_table_head(rpl_parents); 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", 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()); default_instance->of->ocp, curr_rank, curr_dio_interval, uip_ds6_nbr_num());
while(p != NULL) { 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], rpl_get_parent_ipaddr(p)->u8[15],
p->rank, p->rank,
rpl_get_parent_link_metric(p), rpl_get_parent_link_metric(p),
@ -109,7 +110,7 @@ rpl_print_neighbor_list(void)
stats != NULL ? stats->freshness : 0, stats != NULL ? stats->freshness : 0,
link_stats_is_fresh(stats) ? 'f' : ' ', link_stats_is_fresh(stats) ? 'f' : ' ',
p == default_instance->current_dag->preferred_parent ? 'p' : ' ', 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); p = nbr_table_next(rpl_parents, p);
} }
@ -868,6 +869,10 @@ rpl_select_parent(rpl_dag_t *dag)
if(rpl_parent_is_fresh(best)) { if(rpl_parent_is_fresh(best)) {
rpl_set_preferred_parent(dag, best); rpl_set_preferred_parent(dag, best);
dag->rank = rpl_rank_via_parent(dag->preferred_parent); 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 { } else {
rpl_set_preferred_parent(dag, best); rpl_set_preferred_parent(dag, best);

View file

@ -56,6 +56,14 @@
void RPL_CALLBACK_NEW_DIO_INTERVAL(uint8_t dio_interval); void RPL_CALLBACK_NEW_DIO_INTERVAL(uint8_t dio_interval);
#endif /* RPL_CALLBACK_NEW_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; static struct ctimer periodic_timer;
@ -359,42 +367,57 @@ rpl_schedule_unicast_dio_immediately(rpl_instance_t *instance)
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
#if RPL_WITH_PROBING #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) get_probing_target(rpl_dag_t *dag)
{ {
/* Returns the next probing target. The current implementation probes the current /* Returns the next probing target. The current implementation probes the urgent
* preferred parent if we have not updated its link for RPL_PROBING_EXPIRATION_TIME. * probing target if any, or the preferred parent if its link statistics need refresh.
* Otherwise, it picks at random between: * 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 * (2) selecting the least recently updated parent
*/ */
rpl_parent_t *p; rpl_parent_t *p;
rpl_parent_t *probing_target = NULL; rpl_parent_t *probing_target = NULL;
rpl_rank_t probing_target_rank = INFINITE_RANK; 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 probing_target_age = 0;
clock_time_t min_last_tx = clock_time(); clock_time_t clock_now = clock_time();
min_last_tx = min_last_tx > 2 * RPL_PROBING_EXPIRATION_TIME
? min_last_tx - RPL_PROBING_EXPIRATION_TIME : 1;
if(dag == NULL || if(dag == NULL ||
dag->instance == NULL || dag->instance == NULL) {
dag->preferred_parent == NULL) {
return NULL; return NULL;
} }
/* Our preferred parent needs probing */ /* There is an urgent probing target */
if(dag->preferred_parent->last_tx_time < min_last_tx) { if(dag->instance->urgent_probing_target != NULL) {
probing_target = dag->preferred_parent; return dag->instance->urgent_probing_target;
} }
/* With 50% probability: probe best parent not updated for RPL_PROBING_EXPIRATION_TIME */ /* The preferred parent needs probing */
if(probing_target == NULL && (random_rand() % 2) == 0) { 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); p = nbr_table_head(rpl_parents);
while(p != NULL) { 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 */ /* 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 if(probing_target == NULL
|| p_rank < probing_target_rank) { || p_rank < probing_target_rank) {
probing_target = p; 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) { if(probing_target == NULL) {
p = nbr_table_head(rpl_parents); p = nbr_table_head(rpl_parents);
while(p != NULL) { 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 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 = p;
probing_target_age = clock_now - stats->last_tx_time;
} }
} }
p = nbr_table_next(rpl_parents, p); p = nbr_table_next(rpl_parents, p);
@ -431,11 +456,14 @@ handle_probing_timer(void *ptr)
/* Perform probing */ /* Perform probing */
if(target_ipaddr != NULL) { if(target_ipaddr != NULL) {
PRINTF("RPL: probing %u ((last tx %u min ago))\n", PRINTF("RPL: probing %u %s last tx %u min ago\n",
nbr_table_get_lladdr(rpl_parents, probing_target)->u8[7], rpl_get_parent_llpaddr(probing_target)->u8[7],
(unsigned)((clock_time() - probing_target->last_tx_time) / (60 * CLOCK_SECOND))); instance->urgent_probing_target != NULL ? "(urgent)" : "",
/* Send probe (unicast DIO or DIS) */ (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); RPL_PROBING_SEND_FUNC(instance, target_ipaddr);
instance->urgent_probing_target = NULL;
} }
/* Schedule next probing */ /* Schedule next probing */
@ -449,7 +477,7 @@ handle_probing_timer(void *ptr)
void void
rpl_schedule_probing(rpl_instance_t *instance) 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); handle_probing_timer, instance);
} }
#endif /* RPL_WITH_PROBING */ #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 */ clock_time_t dio_next_delay; /* delay for completion of dio interval */
#if RPL_WITH_PROBING #if RPL_WITH_PROBING
struct ctimer probing_timer; struct ctimer probing_timer;
rpl_parent_t *urgent_probing_target;
#endif /* RPL_WITH_PROBING */ #endif /* RPL_WITH_PROBING */
struct ctimer dio_timer; struct ctimer dio_timer;
struct ctimer dao_timer; struct ctimer dao_timer;