rpl_parent_t * rpl_select_parent(rpl_dag_t *dag) { rpl_parent_t *p; rpl_parent_t *best; best = NULL; for(p = list_head(dag->parents); p != NULL; p = p->next) { if(p->rank == INFINITE_RANK) { /* ignore this neighbor */ } else if(best == NULL) { best = p; } else { best = dag->of->best_parent(best, p); } } if(best == NULL) { /* need to handle update of best... */ return NULL; } if(dag->preferred_parent != best) { if(dag->mop != RPL_MOP_NO_DOWNWARD_ROUTES) { PRINTF("RPL: Sending a No-Path DAO to old DAO parent\n"); dao_output(dag->preferred_parent, ZERO_LIFETIME); } dag->preferred_parent = best; /* Cache the value. */ dag->of->update_metric_container(dag); rpl_set_default_route(dag, &best->addr); /* The DAO parent set changed - schedule a DAO transmission. */ if(dag->mop != RPL_MOP_NO_DOWNWARD_ROUTES) { rpl_schedule_dao(dag); } rpl_reset_dio_timer(dag, 1); PRINTF("RPL: New preferred parent, rank changed from %u to %u\n", (unsigned)dag->rank, dag->of->calculate_rank(best, 0)); RPL_STAT(rpl_stats.parent_switch++); } /* Update the DAG rank, since link-layer information may have changed the local confidence. */ dag->rank = dag->of->calculate_rank(best, 0); if(dag->rank < dag->min_rank) { dag->min_rank = dag->rank; } else if(!acceptable_rank(dag, best->rank)) { /* Send a No-Path DAO to the soon-to-be-removed preferred parent. */ if(dag->mop != RPL_MOP_NO_DOWNWARD_ROUTES) { dao_output(best, ZERO_LIFETIME); } remove_parents(dag, 0); return NULL; } return best; }
/*---------------------------------------------------------------------------*/ int rpl_process_parent_event(rpl_instance_t *instance, rpl_parent_t *p) { int return_value; #if DEBUG rpl_rank_t old_rank; old_rank = instance->current_dag->rank; #endif /* DEBUG */ return_value = 1; if(!acceptable_rank(p->dag, p->rank)) { /* The candidate parent is no longer valid: the rank increase resulting from the choice of it as a parent would be too high. */ PRINTF("RPL: Unacceptable rank %u\n", (unsigned)p->rank); rpl_nullify_parent(p); if(p != instance->current_dag->preferred_parent) { return 0; } else { return_value = 0; } } if(rpl_select_dag(instance, p) == NULL) { /* No suitable parent; trigger a local repair. */ PRINTF("RPL: No parents found in any DAG\n"); rpl_local_repair(instance); return 0; } #if DEBUG if(DAG_RANK(old_rank, instance) != DAG_RANK(instance->current_dag->rank, instance)) { PRINTF("RPL: Moving in the instance from rank %hu to %hu\n", DAG_RANK(old_rank, instance), DAG_RANK(instance->current_dag->rank, instance)); if(instance->current_dag->rank != INFINITE_RANK) { PRINTF("RPL: The preferred parent is "); PRINT6ADDR(rpl_get_parent_ipaddr (instance->current_dag->preferred_parent)); PRINTF(" (rank %u)\n", (unsigned)DAG_RANK(instance->current_dag->preferred_parent->rank, instance)); } else { PRINTF("RPL: We don't have any parent"); } } #endif /* DEBUG */ return return_value; }
rpl_parent_t * rpl_select_parent(rpl_dag_t *dag) { rpl_parent_t *p; rpl_parent_t *best; best = NULL; for(p = list_head(dag->parents); p != NULL; p = p->next) { if(best == NULL) { best = p; } else { best = dag->of->best_parent(best, p); } } if(dag->preferred_parent != best) { dag->preferred_parent = best; /* Cache the value. */ dag->of->update_metric_container(dag); rpl_set_default_route(dag, &best->addr); /* The DAO parent set changed - schedule a DAO transmission. */ rpl_schedule_dao(dag); rpl_reset_dio_timer(dag, 1); PRINTF("RPL: New preferred parent, rank changed from %u to %u\n", (unsigned)dag->rank, dag->of->calculate_rank(best, 0)); } /* Update the DAG rank, since link-layer information may have changed the local confidence. */ dag->rank = dag->of->calculate_rank(best, 0); if(dag->rank < dag->min_rank) { dag->min_rank = dag->rank; } else if(!acceptable_rank(dag, best->rank)) { /* Send a No-Path DAO to the soon-to-be-removed preferred parent. */ dao_output(p, ZERO_LIFETIME); remove_parents(dag, 0); return NULL; } return best; }
int rpl_process_parent_event(rpl_dag_t *dag, rpl_parent_t *p) { rpl_rank_t parent_rank; rpl_rank_t old_rank; /* Update the parent rank. */ parent_rank = p->rank; old_rank = dag->rank; if(rpl_select_parent(dag) == NULL) { /* No suitable parent; trigger a local repair. */ PRINTF("RPL: No parents found in a DAG\n"); rpl_local_repair(dag); return 1; } if(DAG_RANK(old_rank, dag) != DAG_RANK(dag->rank, dag)) { if(dag->rank < dag->min_rank) { dag->min_rank = dag->rank; } PRINTF("RPL: Moving in the DAG from rank %hu to %hu\n", DAG_RANK(old_rank, dag), DAG_RANK(dag->rank, dag)); PRINTF("RPL: The preferred parent is "); PRINT6ADDR(&dag->preferred_parent->addr); PRINTF(" (rank %u)\n", (unsigned)DAG_RANK(dag->preferred_parent->rank, dag)); rpl_reset_dio_timer(dag, 1); } if(parent_rank == INFINITE_RANK || !acceptable_rank(dag, dag->of->calculate_rank(NULL, parent_rank))) { /* The candidate parent is no longer valid: the rank increase resulting from the choice of it as a parent would be too high. */ return 0; } return 1; }
/*---------------------------------------------------------------------------*/ rpl_dag_t * rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p) { rpl_parent_t *last_parent; rpl_dag_t *dag, *end, *best_dag; rpl_rank_t old_rank; old_rank = instance->current_dag->rank; last_parent = instance->current_dag->preferred_parent; if(instance->current_dag->rank != ROOT_RANK(instance)) { rpl_select_parent(p->dag); } best_dag = NULL; for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DAG_PER_INSTANCE; dag < end; ++dag) { if(dag->used && dag->preferred_parent != NULL && dag->preferred_parent->rank != INFINITE_RANK) { if(best_dag == NULL) { best_dag = dag; } else { best_dag = instance->of->best_dag(best_dag, dag); } } } if(best_dag == NULL) { /* No parent found: the calling function handle this problem. */ return NULL; } if(instance->current_dag != best_dag) { /* Remove routes installed by DAOs. */ rpl_remove_routes(instance->current_dag); PRINTF("RPL: New preferred DAG: "); PRINT6ADDR(&best_dag->dag_id); PRINTF("\n"); if(best_dag->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) { check_prefix(&instance->current_dag->prefix_info, &best_dag->prefix_info); } else if(instance->current_dag->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) { check_prefix(&instance->current_dag->prefix_info, NULL); } best_dag->joined = 1; instance->current_dag->joined = 0; instance->current_dag = best_dag; } instance->of->update_metric_container(instance); /* Update the DAG rank. */ best_dag->rank = instance->of->calculate_rank(best_dag->preferred_parent, 0); if(last_parent == NULL || best_dag->rank < best_dag->min_rank) { best_dag->min_rank = best_dag->rank; } else if(!acceptable_rank(best_dag, best_dag->rank)) { PRINTF("RPL: New rank unacceptable!\n"); rpl_set_preferred_parent(instance->current_dag, NULL); if(instance->mop != RPL_MOP_NO_DOWNWARD_ROUTES && last_parent != NULL) { /* Send a No-Path DAO to the removed preferred parent. */ dao_output(last_parent, RPL_ZERO_LIFETIME); } return NULL; } if(best_dag->preferred_parent != last_parent) { rpl_set_default_route(instance, rpl_get_parent_ipaddr(best_dag->preferred_parent)); PRINTF("RPL: Changed preferred parent, rank changed from %u to %u\n", (unsigned)old_rank, best_dag->rank); RPL_STAT(rpl_stats.parent_switch++); if(instance->mop != RPL_MOP_NO_DOWNWARD_ROUTES) { if(last_parent != NULL) { /* Send a No-Path DAO to the removed preferred parent. */ dao_output(last_parent, RPL_ZERO_LIFETIME); } /* The DAO parent set changed - schedule a DAO transmission. */ RPL_LOLLIPOP_INCREMENT(instance->dtsn_out); rpl_schedule_dao(instance); } rpl_reset_dio_timer(instance); #if DEBUG rpl_print_neighbor_list(); #endif } else if(best_dag->rank != old_rank) { PRINTF("RPL: Preferred parent update, rank changed from %u to %u\n", (unsigned)old_rank, best_dag->rank); } return best_dag; }