Minor rpl-lite fixes for DAG leaving/joining
This commit is contained in:
parent
38ce63a614
commit
c6537820b1
@ -220,7 +220,7 @@ PT_THREAD(cmd_rpl_set_root(struct pt *pt, shell_output_func output, char *args))
|
||||
} else {
|
||||
if(rpl_dag_root_is_root()) {
|
||||
SHELL_OUTPUT(output, "Setting as non-root node: leaving DAG\n");
|
||||
rpl_dag_leave();
|
||||
rpl_dag_poison_and_leave();
|
||||
} else {
|
||||
SHELL_OUTPUT(output, "Node is not a DAG root\n");
|
||||
}
|
||||
|
@ -88,8 +88,10 @@ rpl_dag_leave(void)
|
||||
LOG_INFO_(", instance %u\n", curr_instance.instance_id);
|
||||
|
||||
/* Issue a no-path DAO */
|
||||
RPL_LOLLIPOP_INCREMENT(curr_instance.dag.dao_curr_seqno);
|
||||
rpl_icmp6_dao_output(0);
|
||||
if(!rpl_dag_root_is_root()) {
|
||||
RPL_LOLLIPOP_INCREMENT(curr_instance.dag.dao_curr_seqno);
|
||||
rpl_icmp6_dao_output(0);
|
||||
}
|
||||
|
||||
/* Forget past link statistics */
|
||||
link_stats_reset();
|
||||
@ -111,6 +113,13 @@ rpl_dag_leave(void)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
rpl_dag_poison_and_leave(void)
|
||||
{
|
||||
curr_instance.dag.state = DAG_POISONING;
|
||||
rpl_timers_schedule_state_update();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
rpl_dag_periodic(unsigned seconds)
|
||||
{
|
||||
if(curr_instance.used) {
|
||||
@ -223,97 +232,98 @@ rpl_dag_ready_to_advertise(void)
|
||||
void
|
||||
rpl_dag_update_state(void)
|
||||
{
|
||||
if(curr_instance.used) {
|
||||
if(!rpl_dag_root_is_root()) {
|
||||
rpl_nbr_t *old_parent = curr_instance.dag.preferred_parent;
|
||||
rpl_rank_t old_rank = curr_instance.dag.rank;
|
||||
rpl_rank_t old_rank;
|
||||
|
||||
/* Any scheduled state update is no longer needed */
|
||||
rpl_timers_unschedule_state_update();
|
||||
if(!curr_instance.used) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(curr_instance.dag.state == DAG_POISONING) {
|
||||
rpl_neighbor_set_preferred_parent(NULL);
|
||||
curr_instance.dag.rank = RPL_INFINITE_RANK;
|
||||
if(old_rank != RPL_INFINITE_RANK) {
|
||||
/* Advertise that we are leaving, and leave after a delay */
|
||||
LOG_WARN("poisoning and leaving after a delay\n");
|
||||
rpl_timers_dio_reset("Poison routes");
|
||||
rpl_timers_schedule_leaving();
|
||||
old_rank = curr_instance.dag.rank;
|
||||
/* Any scheduled state update is no longer needed */
|
||||
rpl_timers_unschedule_state_update();
|
||||
|
||||
if(curr_instance.dag.state == DAG_POISONING) {
|
||||
rpl_neighbor_set_preferred_parent(NULL);
|
||||
curr_instance.dag.rank = RPL_INFINITE_RANK;
|
||||
if(old_rank != RPL_INFINITE_RANK) {
|
||||
/* Advertise that we are leaving, and leave after a delay */
|
||||
LOG_WARN("poisoning and leaving after a delay\n");
|
||||
rpl_timers_dio_reset("Poison routes");
|
||||
rpl_timers_schedule_leaving();
|
||||
}
|
||||
} else if(!rpl_dag_root_is_root()) {
|
||||
rpl_nbr_t *old_parent = curr_instance.dag.preferred_parent;
|
||||
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 {
|
||||
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. */
|
||||
curr_instance.dag.lowest_rank = curr_instance.dag.rank;
|
||||
}
|
||||
|
||||
/* Reset DIO timer in case of significant rank update */
|
||||
if(curr_instance.dag.last_advertised_rank != RPL_INFINITE_RANK
|
||||
&& curr_instance.dag.rank != RPL_INFINITE_RANK
|
||||
&& ABS((int32_t)curr_instance.dag.rank - curr_instance.dag.last_advertised_rank) > RPL_SIGNIFICANT_CHANGE_THRESHOLD) {
|
||||
LOG_WARN("significant rank update %u->%u\n",
|
||||
curr_instance.dag.last_advertised_rank, curr_instance.dag.rank);
|
||||
/* Update already here to avoid multiple resets in a row */
|
||||
curr_instance.dag.last_advertised_rank = curr_instance.dag.rank;
|
||||
rpl_timers_dio_reset("Significant rank update");
|
||||
}
|
||||
|
||||
/* Parent switch */
|
||||
if(curr_instance.dag.preferred_parent != old_parent) {
|
||||
/* We just got a parent (was NULL), reset trickle timer to advertise this */
|
||||
if(old_parent == NULL) {
|
||||
curr_instance.dag.state = DAG_JOINED;
|
||||
rpl_timers_dio_reset("Got parent");
|
||||
LOG_WARN("found parent: ");
|
||||
LOG_WARN_6ADDR(rpl_neighbor_get_ipaddr(curr_instance.dag.preferred_parent));
|
||||
LOG_WARN_(", staying in DAG\n");
|
||||
rpl_timers_unschedule_leaving();
|
||||
}
|
||||
|
||||
/* Schedule a DAO */
|
||||
if(curr_instance.dag.preferred_parent != NULL) {
|
||||
rpl_timers_schedule_dao();
|
||||
} else {
|
||||
/* We have no more parent, schedule DIS to get a chance to hear updated state */
|
||||
curr_instance.dag.state = DAG_INITIALIZED;
|
||||
LOG_WARN("no parent, scheduling periodic DIS, will leave if no parent is found\n");
|
||||
rpl_timers_dio_reset("Poison routes");
|
||||
rpl_timers_schedule_periodic_dis();
|
||||
rpl_timers_schedule_leaving();
|
||||
}
|
||||
|
||||
#if LOG_INFO_ENABLED
|
||||
rpl_neighbor_print_list("Parent switch");
|
||||
#endif /* LOG_INFO_ENABLED */
|
||||
}
|
||||
nbr->better_parent_since = 0; /* Not a better parent */
|
||||
}
|
||||
nbr = nbr_table_next(rpl_neighbors, nbr);
|
||||
}
|
||||
|
||||
/* Finally, update metric container */
|
||||
curr_instance.of->update_metric_container();
|
||||
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. */
|
||||
curr_instance.dag.lowest_rank = curr_instance.dag.rank;
|
||||
}
|
||||
|
||||
/* Reset DIO timer in case of significant rank update */
|
||||
if(curr_instance.dag.last_advertised_rank != RPL_INFINITE_RANK
|
||||
&& curr_instance.dag.rank != RPL_INFINITE_RANK
|
||||
&& ABS((int32_t)curr_instance.dag.rank - curr_instance.dag.last_advertised_rank) > RPL_SIGNIFICANT_CHANGE_THRESHOLD) {
|
||||
LOG_WARN("significant rank update %u->%u\n",
|
||||
curr_instance.dag.last_advertised_rank, curr_instance.dag.rank);
|
||||
/* Update already here to avoid multiple resets in a row */
|
||||
curr_instance.dag.last_advertised_rank = curr_instance.dag.rank;
|
||||
rpl_timers_dio_reset("Significant rank update");
|
||||
}
|
||||
|
||||
/* Parent switch */
|
||||
if(curr_instance.dag.preferred_parent != old_parent) {
|
||||
/* We just got a parent (was NULL), reset trickle timer to advertise this */
|
||||
if(old_parent == NULL) {
|
||||
curr_instance.dag.state = DAG_JOINED;
|
||||
rpl_timers_dio_reset("Got parent");
|
||||
LOG_WARN("found parent: ");
|
||||
LOG_WARN_6ADDR(rpl_neighbor_get_ipaddr(curr_instance.dag.preferred_parent));
|
||||
LOG_WARN_(", staying in DAG\n");
|
||||
rpl_timers_unschedule_leaving();
|
||||
}
|
||||
|
||||
/* Schedule a DAO */
|
||||
if(curr_instance.dag.preferred_parent != NULL) {
|
||||
rpl_timers_schedule_dao();
|
||||
} else {
|
||||
/* We have no more parent, schedule DIS to get a chance to hear updated state */
|
||||
curr_instance.dag.state = DAG_INITIALIZED;
|
||||
LOG_WARN("no parent, scheduling periodic DIS, will leave if no parent is found\n");
|
||||
rpl_timers_dio_reset("Poison routes");
|
||||
rpl_timers_schedule_periodic_dis();
|
||||
rpl_timers_schedule_leaving();
|
||||
}
|
||||
|
||||
#if LOG_INFO_ENABLED
|
||||
rpl_neighbor_print_list("Parent switch");
|
||||
#endif /* LOG_INFO_ENABLED */
|
||||
}
|
||||
}
|
||||
|
||||
/* Finally, update metric container */
|
||||
curr_instance.of->update_metric_container();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static rpl_nbr_t *
|
||||
|
@ -57,6 +57,11 @@
|
||||
* \return The description string
|
||||
*/
|
||||
const char *rpl_dag_state_to_str(enum rpl_dag_state state);
|
||||
/**
|
||||
* Start poisoning and leave the DAG after a delay
|
||||
*
|
||||
*/
|
||||
void rpl_dag_poison_and_leave(void);
|
||||
/**
|
||||
* Leaves the current DAG
|
||||
*
|
||||
|
@ -557,10 +557,19 @@ rpl_icmp6_dao_output(uint8_t lifetime)
|
||||
/* Make sure we're up-to-date before sending data out */
|
||||
rpl_dag_update_state();
|
||||
|
||||
if(!curr_instance.used || curr_instance.dag.preferred_parent == NULL
|
||||
|| prefix == NULL || parent_ipaddr == NULL || curr_instance.mop == RPL_MOP_NO_DOWNWARD_ROUTES) {
|
||||
LOG_WARN("rpl_icmp6_dao_output: node not ready to send a DAO (used %u, pref parent %u, prefix %u, mop %u)\n",
|
||||
curr_instance.used, curr_instance.dag.preferred_parent != NULL && parent_ipaddr != NULL, prefix != NULL, curr_instance.mop);
|
||||
if(!curr_instance.used) {
|
||||
LOG_WARN("rpl_icmp6_dao_output: not in an instance, skip sending DAO\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(curr_instance.dag.preferred_parent == NULL) {
|
||||
LOG_WARN("rpl_icmp6_dao_output: no preferred parent, skip sending DAO\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(prefix == NULL || parent_ipaddr == NULL || curr_instance.mop == RPL_MOP_NO_DOWNWARD_ROUTES) {
|
||||
LOG_WARN("rpl_icmp6_dao_output: node not ready to send a DAO (prefix %p, parent addr %p, mop %u)\n",
|
||||
prefix, parent_ipaddr, curr_instance.mop);
|
||||
return;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user