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:
parent
426e10c3ed
commit
c5cf8608e9
|
@ -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
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue