45 #include "net/rpl/rpl-private.h"
55 #define DEBUG DEBUG_NONE
61 extern rpl_of_t RPL_OF;
62 static rpl_of_t *
const objective_functions[] = {&RPL_OF};
65 #ifndef RPL_CONF_MAX_DAG_ENTRIES
66 #define RPL_MAX_DAG_ENTRIES 2
68 #define RPL_MAX_DAG_ENTRIES RPL_CONF_MAX_DAG_ENTRIES
71 #ifndef RPL_CONF_MAX_PARENTS
72 #define RPL_MAX_PARENTS 8
74 #define RPL_MAX_PARENTS RPL_CONF_MAX_PARENTS
79 #ifndef RPL_CONF_GROUNDED
80 #define RPL_GROUNDED 0
82 #define RPL_GROUNDED RPL_CONF_GROUNDED
85 #ifndef RPL_CONF_DIO_INTERVAL_MIN
86 #define RPL_DIO_INTERVAL_MIN DEFAULT_DIO_INTERVAL_MIN
88 #define RPL_DIO_INTERVAL_MIN RPL_CONF_DIO_INTERVAL_MIN
91 #ifndef RPL_CONF_DIO_INTERVAL_DOUBLINGS
92 #define RPL_DIO_INTERVAL_DOUBLINGS DEFAULT_DIO_INTERVAL_DOUBLINGS
94 #define RPL_DIO_INTERVAL_DOUBLINGS RPL_CONF_DIO_INTERVAL_DOUBLINGS
99 MEMB(parent_memb,
struct rpl_parent, RPL_MAX_PARENTS);
101 static rpl_dag_t dag_table[RPL_MAX_DAG_ENTRIES];
105 remove_parents(rpl_dag_t *dag, rpl_rank_t minimum_rank)
107 rpl_parent_t *p, *p2;
109 PRINTF(
"RPL: Removing parents (minimum rank %u)\n",
114 if(p->rank >= minimum_rank) {
115 rpl_remove_parent(dag, p);
121 remove_worst_parent(rpl_dag_t *dag, rpl_rank_t min_worst_rank)
123 rpl_parent_t *p, *worst;
125 PRINTF(
"RPL: Removing the worst parent\n");
130 if(p != dag->preferred_parent &&
131 (worst ==
NULL || p->rank > worst->rank)) {
137 if(worst !=
NULL && worst->rank > min_worst_rank) {
138 rpl_remove_parent(dag, worst);
143 should_send_dao(rpl_dag_t *dag, rpl_dio_t *dio, rpl_parent_t *p)
146 if(dag->mop == RPL_MOP_NO_DOWNWARD_ROUTES)
return 0;
147 return dio->dtsn != p->dtsn && p == dag->preferred_parent;
151 acceptable_rank(rpl_dag_t *dag, rpl_rank_t rank)
153 return rank != INFINITE_RANK &&
154 (dag->max_rankinc == 0 ||
155 DAG_RANK(rank, dag) <= DAG_RANK(dag->min_rank + dag->max_rankinc, dag));
165 dag = rpl_get_dag(RPL_DEFAULT_INSTANCE);
167 PRINTF(
"RPL: Dropping a joined DAG when setting this node as root");
168 version = dag->version;
172 dag = rpl_alloc_dag(RPL_DEFAULT_INSTANCE);
174 PRINTF(
"RPL: Failed to allocate a DAG\n");
179 dag->version = version + 1;
180 dag->grounded = RPL_GROUNDED;
181 dag->mop = RPL_MOP_DEFAULT;
183 dag->preferred_parent =
NULL;
186 memcpy(&dag->dag_id, dag_id,
sizeof(dag->dag_id));
188 dag->dio_intdoubl = DEFAULT_DIO_INTERVAL_DOUBLINGS;
189 dag->dio_intmin = DEFAULT_DIO_INTERVAL_MIN;
190 dag->dio_redundancy = DEFAULT_DIO_REDUNDANCY;
191 dag->max_rankinc = DEFAULT_MAX_RANKINC;
192 dag->min_hoprankinc = DEFAULT_MIN_HOPRANKINC;
194 dag->default_lifetime = RPL_DEFAULT_LIFETIME;
195 dag->lifetime_unit = RPL_DEFAULT_LIFETIME_UNIT;
197 dag->rank = ROOT_RANK(dag);
199 dag->of->update_metric_container(dag);
201 PRINTF(
"RPL: Node set to be a DAG root with DAG ID ");
202 PRINT6ADDR(&dag->dag_id);
205 ANNOTATE(
"#A root=%u\n",dag->dag_id.u8[
sizeof(dag->dag_id) - 1]);
208 rpl_reset_dio_timer(dag, 1);
214 rpl_set_prefix(rpl_dag_t *dag,
uip_ipaddr_t *prefix,
int len)
217 memset(&dag->prefix_info.prefix, 0, 16);
218 memcpy(&dag->prefix_info.prefix, prefix, (len + 7) / 8);
219 dag->prefix_info.length = len;
220 dag->prefix_info.flags = UIP_ND6_RA_FLAG_AUTONOMOUS;
221 PRINTF(
"RPL: Prefix set - will announce this in DIOs\n");
228 rpl_set_default_route(rpl_dag_t *dag,
uip_ipaddr_t *from)
230 if(dag->def_route !=
NULL) {
231 PRINTF(
"RPL: Removing default route through ");
232 PRINT6ADDR(&dag->def_route->ipaddr);
234 uip_ds6_defrt_rm(dag->def_route);
238 PRINTF(
"RPL: Adding default route through ");
241 dag->def_route = uip_ds6_defrt_add(from,
243 dag->default_lifetime));
244 if(dag->def_route ==
NULL) {
253 rpl_alloc_dag(uint8_t instance_id)
258 for(dag = &dag_table[0], end = dag + RPL_MAX_DAG_ENTRIES; dag < end; dag++) {
260 memset(dag, 0,
sizeof(*dag));
261 dag->parents = &dag->parent_list;
263 dag->instance_id = instance_id;
264 dag->def_route =
NULL;
265 dag->rank = INFINITE_RANK;
266 dag->min_rank = INFINITE_RANK;
271 RPL_STAT(rpl_stats.mem_overflows++);
276 rpl_free_dag(rpl_dag_t *dag)
278 PRINTF(
"RPL: Leaving the DAG ");
279 PRINT6ADDR(&dag->dag_id);
283 rpl_remove_routes(dag);
286 remove_parents(dag, 0);
287 rpl_set_default_route(dag,
NULL);
297 rpl_add_parent(rpl_dag_t *dag, rpl_dio_t *dio,
uip_ipaddr_t *addr)
303 RPL_STAT(rpl_stats.mem_overflows++);
307 memcpy(&p->addr, addr,
sizeof(p->addr));
310 p->link_metric = INITIAL_LINK_METRIC;
313 memcpy(&p->mc, &dio->mc,
sizeof(p->mc));
336 rpl_select_parent(rpl_dag_t *dag)
343 if(p->rank == INFINITE_RANK) {
345 }
else if(best ==
NULL) {
348 best = dag->of->best_parent(best, p);
357 if(dag->preferred_parent != best) {
358 PRINTF(
"RPL: Sending a No-Path DAO to old DAO parent\n");
359 dao_output(dag->preferred_parent, ZERO_LIFETIME);
361 dag->preferred_parent = best;
362 dag->of->update_metric_container(dag);
363 rpl_set_default_route(dag, &best->addr);
365 if(dag->mop != RPL_MOP_NO_DOWNWARD_ROUTES) {
366 rpl_schedule_dao(dag);
368 rpl_reset_dio_timer(dag, 1);
369 PRINTF(
"RPL: New preferred parent, rank changed from %u to %u\n",
370 (
unsigned)dag->rank, dag->of->calculate_rank(best, 0));
371 RPL_STAT(rpl_stats.parent_switch++);
376 dag->rank = dag->of->calculate_rank(best, 0);
377 if(dag->rank < dag->min_rank) {
378 dag->min_rank = dag->rank;
379 }
else if(!acceptable_rank(dag, best->rank)) {
381 dao_output(best, ZERO_LIFETIME);
383 remove_parents(dag, 0);
391 rpl_remove_parent(rpl_dag_t *dag, rpl_parent_t *parent)
396 uip_ds6_route_rm_by_nexthop(&parent->addr);
397 defrt = uip_ds6_defrt_lookup(&parent->addr);
399 PRINTF(
"RPL: Removing default route ");
400 PRINT6ADDR(&parent->addr);
402 uip_ds6_defrt_rm(defrt);
403 dag->def_route =
NULL;
406 PRINTF(
"RPL: Removing parent ");
407 PRINT6ADDR(&parent->addr);
410 if(parent == dag->preferred_parent) {
411 dag->preferred_parent =
NULL;
420 rpl_get_dag(
int instance_id)
424 for(i = 0; i < RPL_MAX_DAG_ENTRIES; i++) {
425 if(dag_table[i].joined && (instance_id == RPL_ANY_INSTANCE ||
426 dag_table[i].instance_id == instance_id)) {
427 return &dag_table[i];
434 rpl_find_of(rpl_ocp_t ocp)
439 i <
sizeof(objective_functions) /
sizeof(objective_functions[0]);
441 if(objective_functions[i]->ocp == ocp) {
442 return objective_functions[i];
456 dag = rpl_alloc_dag(dio->instance_id);
458 PRINTF(
"RPL: Failed to allocate a DAG object!\n");
462 p = rpl_add_parent(dag, dio, from);
463 PRINTF(
"RPL: Adding ");
465 PRINTF(
" as a parent: ");
470 PRINTF(
"succeeded\n");
474 of = rpl_find_of(dio->ocp);
476 PRINTF(
"RPL: DIO for DAG instance %u does not specify a supported OF\n",
483 if((dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS)) {
486 memcpy(&ipaddr, &dio->prefix_info.prefix, 16);
488 if(uip_ds6_addr_lookup(&ipaddr) ==
NULL) {
489 PRINTF(
"RPL: adding global IP address ");
492 uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF);
499 dag->grounded = dio->grounded;
501 dag->preference = dio->preference;
502 dag->instance_id = dio->instance_id;
504 dag->max_rankinc = dio->dag_max_rankinc;
505 dag->min_hoprankinc = dio->dag_min_hoprankinc;
507 dag->version = dio->version;
508 dag->preferred_parent = p;
509 dag->of->update_metric_container(dag);
511 dag->dio_intdoubl = dio->dag_intdoubl;
512 dag->dio_intmin = dio->dag_intmin;
513 dag->dio_redundancy = dio->dag_redund;
515 memcpy(&dag->dag_id, &dio->dag_id,
sizeof(dio->dag_id));
518 memcpy(&dag->prefix_info, &dio->prefix_info,
sizeof(rpl_prefix_t));
520 dag->rank = dag->of->calculate_rank(p, dio->rank);
521 dag->min_rank = dag->rank;
523 PRINTF(
"RPL: Joined DAG with instance ID %u, rank %hu, DAG ID ",
524 dio->instance_id, dag->rank);
525 PRINT6ADDR(&dag->dag_id);
528 ANNOTATE(
"#A join=%u\n",dag->dag_id.u8[
sizeof(dag->dag_id) - 1]);
531 dag->default_lifetime = dio->default_lifetime;
532 dag->lifetime_unit = dio->lifetime_unit;
534 rpl_reset_dio_timer(dag, 1);
535 rpl_set_default_route(dag, from);
537 if(should_send_dao(dag, dio, p)) {
538 rpl_schedule_dao(dag);
540 PRINTF(
"RPL: The DIO does not meet the prerequisites for sending a DAO\n");
545 global_repair(
uip_ipaddr_t *from, rpl_dag_t *dag, rpl_dio_t *dio)
549 remove_parents(dag, 0);
550 dag->version = dio->version;
553 if((p = rpl_add_parent(dag, dio, from)) ==
NULL) {
554 PRINTF(
"RPL: Failed to add a parent during the global repair\n");
555 dag->rank = INFINITE_RANK;
557 rpl_set_default_route(dag, from);
558 dag->rank = dag->of->calculate_rank(
NULL, dio->rank);
559 dag->min_rank = dag->rank;
560 rpl_reset_dio_timer(dag, 1);
561 if(should_send_dao(dag, dio, p)) {
562 rpl_schedule_dao(dag);
565 PRINTF(
"RPL: Participating in a global repair (version=%u, rank=%hu)\n",
566 dag->version, dag->rank);
568 RPL_STAT(rpl_stats.global_repairs++);
572 rpl_repair_dag(rpl_dag_t *dag)
574 if(dag->rank == ROOT_RANK(dag)) {
577 rpl_reset_dio_timer(dag, 1);
584 rpl_local_repair(rpl_dag_t *dag)
586 PRINTF(
"RPL: Starting a local DAG repair\n");
588 dag->rank = INFINITE_RANK;
589 remove_parents(dag, 0);
590 rpl_reset_dio_timer(dag, 1);
592 RPL_STAT(rpl_stats.local_repairs++);
596 rpl_recalculate_ranks(
void)
606 dag = rpl_get_dag(RPL_ANY_INSTANCE);
611 rpl_process_parent_event(dag, p);
624 rpl_process_parent_event(rpl_dag_t *dag, rpl_parent_t *p)
626 rpl_rank_t parent_rank;
630 parent_rank = p->rank;
631 old_rank = dag->rank;
633 if(rpl_select_parent(dag) ==
NULL) {
635 PRINTF(
"RPL: No parents found in a DAG\n");
636 rpl_local_repair(dag);
640 if(DAG_RANK(old_rank, dag) != DAG_RANK(dag->rank, dag)) {
641 if(dag->rank < dag->min_rank) {
642 dag->min_rank = dag->rank;
644 PRINTF(
"RPL: Moving in the DAG from rank %hu to %hu\n",
645 DAG_RANK(old_rank, dag), DAG_RANK(dag->rank, dag));
646 PRINTF(
"RPL: The preferred parent is ");
647 PRINT6ADDR(&dag->preferred_parent->addr);
648 PRINTF(
" (rank %u)\n",
649 (
unsigned)DAG_RANK(dag->preferred_parent->rank, dag));
650 rpl_reset_dio_timer(dag, 1);
653 if(parent_rank == INFINITE_RANK ||
654 !acceptable_rank(dag, dag->of->calculate_rank(
NULL, parent_rank))) {
669 if(dio->mop != RPL_MOP_DEFAULT) {
670 PRINTF(
"RPL: Ignoring a DIO with an unsupported MOP: %d\n", dio->mop);
674 dag = rpl_get_dag(dio->instance_id);
677 if(dio->rank != INFINITE_RANK) {
680 PRINTF(
"RPL: Ignoring DIO from node with infinite rank: ");
687 if(memcmp(&dag->dag_id, &dio->dag_id,
sizeof(dag->dag_id))) {
688 PRINTF(
"RPL: Ignoring DIO for another DAG within our instance\n");
692 if(dio->version > dag->version) {
693 if(dag->rank == ROOT_RANK(dag)) {
694 PRINTF(
"RPL: Root received inconsistent DIO version number\n");
695 dag->version = dio->version + 1;
696 rpl_reset_dio_timer(dag, 1);
698 global_repair(from, dag, dio);
701 }
else if(dio->version < dag->version) {
703 PRINTF(
"RPL: old version received => inconsistency detected\n");
704 rpl_reset_dio_timer(dag, 1);
708 if(dio->rank == INFINITE_RANK) {
709 rpl_reset_dio_timer(dag, 1);
710 }
else if(dio->rank < ROOT_RANK(dag)) {
711 PRINTF(
"RPL: Ignoring DIO with too low rank: %u\n",
712 (
unsigned)dio->rank);
716 if(dag->rank == ROOT_RANK(dag)) {
717 if(dio->rank != INFINITE_RANK) {
730 p = rpl_find_parent(dag, from);
732 if(RPL_PARENT_COUNT(dag) == RPL_MAX_PARENTS) {
734 remove_worst_parent(dag, dio->rank);
738 p = rpl_add_parent(dag, dio, from);
740 PRINTF(
"RPL: Failed to add a new parent (");
746 PRINTF(
"RPL: New candidate parent with rank %u: ", (
unsigned)p->rank);
749 }
else if(DAG_RANK(p->rank, dag) == DAG_RANK(dio->rank, dag)) {
750 PRINTF(
"RPL: Received consistent DIO\n");
756 memcpy(&p->mc, &dio->mc,
sizeof(p->mc));
758 if(rpl_process_parent_event(dag, p) == 0) {
763 if(should_send_dao(dag, dio, p)) {
764 rpl_schedule_dao(dag);