From a0b0ddbbead97795ed0700fa72f9765ccb3a5429 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 27 Jun 2017 19:22:56 +0200 Subject: [PATCH] RPL-lite MRHOF: added time hysteresis --- core/net/rpl-lite/rpl-dag.c | 17 ++++++++++++ core/net/rpl-lite/rpl-mrhof.c | 45 ++++++++++++++++++++++---------- core/net/rpl-lite/rpl-neighbor.c | 9 +++++-- core/net/rpl-lite/rpl-types.h | 3 +++ 4 files changed, 58 insertions(+), 16 deletions(-) diff --git a/core/net/rpl-lite/rpl-dag.c b/core/net/rpl-lite/rpl-dag.c index 5245c5689..992d485c7 100644 --- a/core/net/rpl-lite/rpl-dag.c +++ b/core/net/rpl-lite/rpl-dag.c @@ -238,11 +238,28 @@ rpl_dag_update_state(void) rpl_timers_schedule_leaving(); } } else { + rpl_nbr_t *nbr; + /* Select and set preferred parent */ rpl_neighbor_set_preferred_parent(rpl_neighbor_select_best()); /* Update rank */ curr_instance.dag.rank = rpl_neighbor_rank_via_nbr(curr_instance.dag.preferred_parent); + /* Update better_parent_since flag for each neighbor */ + nbr = nbr_table_head(rpl_neighbors); + while(nbr != NULL) { + if(rpl_neighbor_rank_via_nbr(nbr) < curr_instance.dag.rank) { + /* This neighbor would be a better parent than our current. + Set 'better_parent_since' if not already set. */ + if(nbr->better_parent_since == 0) { + nbr->better_parent_since = clock_time(); /* Initialize */ + } + } else { + nbr->better_parent_since = 0; /* Not a better parent */ + } + nbr = nbr_table_next(rpl_neighbors, nbr); + } + if(old_parent == NULL || curr_instance.dag.rank < curr_instance.dag.lowest_rank) { /* This is a slight departure from RFC6550: if we had no preferred parent before, * reset lowest_rank. This helps recovering from temporary bad link conditions. */ diff --git a/core/net/rpl-lite/rpl-mrhof.c b/core/net/rpl-lite/rpl-mrhof.c index 4700c2466..3784a94f8 100644 --- a/core/net/rpl-lite/rpl-mrhof.c +++ b/core/net/rpl-lite/rpl-mrhof.c @@ -82,11 +82,16 @@ #if !RPL_MRHOF_SQUARED_ETX /* Hysteresis of MRHOF: the rank must differ more than PARENT_SWITCH_THRESHOLD_DIV * in order to switch preferred parent. Default in RFC6719: 192, eq ETX of 1.5. */ -#define PARENT_SWITCH_THRESHOLD 192 /* Eq ETX of 1.5 */ +#define RANK_THRESHOLD 192 /* Eq ETX of 1.5 */ #else /* !RPL_MRHOF_SQUARED_ETX */ -#define PARENT_SWITCH_THRESHOLD 384 /* Eq ETX of sqrt(3) */ +#define RANK_THRESHOLD 384 /* Eq ETX of sqrt(3) */ #endif /* !RPL_MRHOF_SQUARED_ETX */ +/* Additional, custom hysteresis based on time. If a neighbor was consistently + * better than our preferred parent for at least TIME_THRESHOLD, switch to + * this neighbor regardless of RANK_THRESHOLD. */ +#define TIME_THRESHOLD (10 * 60 * CLOCK_SECOND) + /*---------------------------------------------------------------------------*/ static void reset(void) @@ -175,11 +180,24 @@ nbr_is_acceptable_parent(rpl_nbr_t *nbr) return nbr_has_usable_link(nbr) && path_cost <= MAX_PATH_COST; } /*---------------------------------------------------------------------------*/ +static int +within_hysteresis(rpl_nbr_t *nbr) +{ + uint16_t path_cost = nbr_path_cost(nbr); + uint16_t parent_path_cost = nbr_path_cost(curr_instance.dag.preferred_parent); + + int within_rank_hysteresis = path_cost + RANK_THRESHOLD > parent_path_cost; + int within_time_hysteresis = nbr->better_parent_since == 0 + || (clock_time() - nbr->better_parent_since) <= TIME_THRESHOLD; + + /* As we want to consider neighbors that are either beyond the rank or time + hystereses, return 1 here iff the neighbor is within both hystereses. */ + return within_rank_hysteresis && within_time_hysteresis; +} +/*---------------------------------------------------------------------------*/ static rpl_nbr_t * best_parent(rpl_nbr_t *nbr1, rpl_nbr_t *nbr2) { - uint16_t nbr1_cost; - uint16_t nbr2_cost; int nbr1_is_acceptable; int nbr2_is_acceptable; @@ -193,18 +211,17 @@ best_parent(rpl_nbr_t *nbr1, rpl_nbr_t *nbr2) return nbr1_is_acceptable ? nbr1 : NULL; } - nbr1_cost = nbr_path_cost(nbr1); - nbr2_cost = nbr_path_cost(nbr2); - - /* Maintain stability of the preferred parent in case of similar ranks. */ - if(nbr1 == curr_instance.dag.preferred_parent || nbr2 == curr_instance.dag.preferred_parent) { - if(nbr1_cost < nbr2_cost + PARENT_SWITCH_THRESHOLD && - nbr1_cost > nbr2_cost - PARENT_SWITCH_THRESHOLD) { - return curr_instance.dag.preferred_parent; - } + /* Maintain stability of the preferred parent. Switch only if the gain + is greater than RANK_THRESHOLD, or if the neighbor has been better than the + current parent for at more than TIME_THRESHOLD. */ + if(nbr1 == curr_instance.dag.preferred_parent && within_hysteresis(nbr2)) { + return nbr1; + } + if(nbr2 == curr_instance.dag.preferred_parent && within_hysteresis(nbr1)) { + return nbr2; } - return nbr1_cost < nbr2_cost ? nbr1 : nbr2; + return nbr_path_cost(nbr1) < nbr_path_cost(nbr2) ? nbr1 : nbr2; } /*---------------------------------------------------------------------------*/ #if !RPL_WITH_MC diff --git a/core/net/rpl-lite/rpl-neighbor.c b/core/net/rpl-lite/rpl-neighbor.c index 457d2c634..c4b28c0e6 100644 --- a/core/net/rpl-lite/rpl-neighbor.c +++ b/core/net/rpl-lite/rpl-neighbor.c @@ -108,9 +108,14 @@ rpl_neighbor_print_list(const char *str) nbr == curr_instance.dag.preferred_parent ? 'p' : ' ' ); if(stats->last_tx_time > 0) { - LOG_INFO_(" (last tx %u min ago)\n", (unsigned)((clock_now - stats->last_tx_time) / (60 * CLOCK_SECOND))); + LOG_INFO_(" (last tx %u min ago", (unsigned)((clock_now - stats->last_tx_time) / (60 * CLOCK_SECOND))); } else { - LOG_INFO_(" (no tx)\n"); + LOG_INFO_(" (no tx"); + } + if(nbr->better_parent_since > 0) { + LOG_INFO_(", better since %u min)\n", (unsigned)((clock_now - nbr->better_parent_since) / (60 * CLOCK_SECOND))); + } else { + LOG_INFO_(")\n"); } nbr = nbr_table_next(rpl_neighbors, nbr); } diff --git a/core/net/rpl-lite/rpl-types.h b/core/net/rpl-lite/rpl-types.h index 66aebbe23..6256eaf0e 100644 --- a/core/net/rpl-lite/rpl-types.h +++ b/core/net/rpl-lite/rpl-types.h @@ -132,6 +132,9 @@ typedef struct rpl_prefix rpl_prefix_t; /* All information related to a RPL neighbor */ struct rpl_nbr { + clock_time_t better_parent_since; /* The neighbor has been a possible + replacement for our preferred parent consistently since 'parent_since'. + Currently used by MRHOF only. */ #if RPL_WITH_MC rpl_metric_container_t mc; #endif /* RPL_WITH_MC */