diff --git a/core/net/rpl/rpl-conf.h b/core/net/rpl/rpl-conf.h index 4474d1449..78f032252 100644 --- a/core/net/rpl/rpl-conf.h +++ b/core/net/rpl/rpl-conf.h @@ -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 /* diff --git a/core/net/rpl/rpl-dag.c b/core/net/rpl/rpl-dag.c index e7fc60a96..6bbc99fab 100644 --- a/core/net/rpl/rpl-dag.c +++ b/core/net/rpl/rpl-dag.c @@ -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); diff --git a/core/net/rpl/rpl-timers.c b/core/net/rpl/rpl-timers.c index 6369f32fb..f5f017535 100644 --- a/core/net/rpl/rpl-timers.c +++ b/core/net/rpl/rpl-timers.c @@ -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 */ diff --git a/core/net/rpl/rpl.h b/core/net/rpl/rpl.h index dce9d1354..f4efafd50 100644 --- a/core/net/rpl/rpl.h +++ b/core/net/rpl/rpl.h @@ -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;