From e000b1abf32400e6530c7cf614ebc89a57767dc6 Mon Sep 17 00:00:00 2001 From: nvt-se Date: Mon, 14 Jun 2010 12:44:37 +0000 Subject: [PATCH] A major update to ContikiRPL resulting in a reduced code footprint by 300 bytes, as well as cleaner protocol logic. * Made parent management uniform. * Simplified the DIO processing. * Improved the Objective Function API and its documentation. * Removed redundant code at various places. * Improved identifier naming. * Switched visualization from candidate parents to preferred parents only. * Made DAO ACK transmissions configurable. * Improved initial ETX guess by using a cached local confidence value. * Added a periodical rank recalculation function to reduce the maximum stack depth. * Increased the Trickle redundancy constant to ensure faster topological updates. --- core/net/rpl/rpl-dag.c | 388 +++++++++++++++++++------------------- core/net/rpl/rpl-icmp6.c | 45 +++-- core/net/rpl/rpl-of-etx.c | 62 ++++-- core/net/rpl/rpl-of0.c | 31 +-- core/net/rpl/rpl-timers.c | 17 +- core/net/rpl/rpl.c | 38 +--- core/net/rpl/rpl.h | 54 ++++-- 7 files changed, 335 insertions(+), 300 deletions(-) diff --git a/core/net/rpl/rpl-dag.c b/core/net/rpl/rpl-dag.c index e0bd305c9..ac69278d1 100644 --- a/core/net/rpl/rpl-dag.c +++ b/core/net/rpl/rpl-dag.c @@ -32,7 +32,7 @@ * * This file is part of the Contiki operating system. * - * $Id: rpl-dag.c,v 1.26 2010/06/14 11:35:21 adamdunkels Exp $ + * $Id: rpl-dag.c,v 1.27 2010/06/14 12:44:37 nvt-se Exp $ */ /** * \file @@ -45,15 +45,14 @@ #include "net/uip.h" #include "net/uip-nd6.h" -#include "sys/ctimer.h" #include "lib/list.h" #include "lib/memb.h" +#include "sys/ctimer.h" #include #include #define DEBUG DEBUG_ANNOTATE - #include "net/uip-debug.h" /************************************************************************/ @@ -68,7 +67,7 @@ static rpl_of_t *objective_functions[] = {&rpl_of_etx, NULL}; #endif /* !RPL_CONF_MAX_DAG_ENTRIES */ #ifndef RPL_CONF_MAX_PARENTS -#define RPL_MAX_PARENTS 4 +#define RPL_MAX_PARENTS 8 #else #define RPL_MAX_PARENTS RPL_CONF_MAX_PARENTS #endif /* !RPL_CONF_MAX_PARENTS */ @@ -97,31 +96,32 @@ static rpl_of_t *objective_functions[] = {&rpl_of_etx, NULL}; MEMB(parent_memb, struct rpl_parent, RPL_MAX_PARENTS); static rpl_dag_t dag_table[RPL_MAX_DAG_ENTRIES]; - -#define POISON_ROUTES 1 /************************************************************************/ +/* Remove DAG parents with a rank that is at least the same as minimum_rank. + * If the argument poison_routes is non-null, the function also sends + * no-DAOs to these parents. + */ +#define POISON_ROUTES 1 + static void -remove_parents(rpl_dag_t *dag, rpl_parent_t *exception, int poison_routes) +remove_parents(rpl_dag_t *dag, rpl_rank_t minimum_rank, int poison_routes) { rpl_parent_t *p, *p2; - PRINTF("RPL: Removing parents %s poisoning routes\n", - poison_routes == POISON_ROUTES ? "and" : "without"); + PRINTF("RPL: Removing parents (minimum rank %u, poisoning routes %d\n", + minimum_rank, poison_routes); - for(p = list_head(dag->parents); p != NULL;) { - if(p != exception) { - if(poison_routes == POISON_ROUTES) { - /* Send no-DAOs to old parents. */ - dao_output(p, ZERO_LIFETIME); - } + for(p = list_head(dag->parents); p != NULL; p = p2) { + p2 = p->next; + if(p->rank >= minimum_rank) { + if(poison_routes == POISON_ROUTES) { + /* Send no-DAOs to old parents. */ + dao_output(p, ZERO_LIFETIME); + } - p2 = p->next; - rpl_remove_parent(dag, p); - p = p2; - } else { - p = p->next; - } - } + rpl_remove_parent(dag, p); + } + } } /************************************************************************/ static int @@ -129,14 +129,13 @@ should_send_dao(rpl_dag_t *dag, rpl_dio_t *dio, rpl_parent_t *p) { return 1; return dio->dst_adv_supported && dio->dst_adv_trigger && - dio->dtsn > p->dtsn && p == dag->best_parent; + dio->dtsn > p->dtsn && p == dag->preferred_parent; } /************************************************************************/ static int -acceptable_rank_increase(rpl_dag_t *dag, rpl_parent_t *p) +acceptable_rank(rpl_dag_t *dag, rpl_rank_t rank) { - return !dag->max_rankinc || - dag->of->increment_rank(p->rank, p) <= dag->min_rank + dag->max_rankinc; + return rank != INFINITE_RANK && rank <= dag->min_rank + dag->max_rankinc; } /************************************************************************/ rpl_dag_t * @@ -164,7 +163,7 @@ rpl_set_root(uip_ipaddr_t *dag_id) dag->grounded = RPL_GROUNDED; dag->rank = ROOT_RANK; dag->of = rpl_find_of(RPL_DEFAULT_OCP); - dag->best_parent = NULL; + dag->preferred_parent = NULL; dag->dtsn_out = 1; /* Trigger DAOs from the beginning. */ memcpy(&dag->dag_id, dag_id, sizeof(dag->dag_id)); @@ -228,16 +227,19 @@ rpl_set_default_route(rpl_dag_t *dag, uip_ipaddr_t *from) rpl_dag_t * rpl_alloc_dag(uint8_t instance_id) { - int i; + rpl_dag_t *dag; + rpl_dag_t *end; - for(i = 0; i < RPL_MAX_DAG_ENTRIES; i++) { - if(dag_table[i].used == 0) { - memset(&dag_table[i], 0, sizeof(dag_table[0])); - dag_table[i].parents = &dag_table[i].parent_list; - list_init(dag_table[i].parents); - dag_table[i].instance_id = instance_id; - dag_table[i].def_route = NULL; - return &dag_table[i]; + for(dag = &dag_table[0], end = dag + RPL_MAX_DAG_ENTRIES; dag < end; dag++) { + if(dag->used == 0) { + memset(dag, 0, sizeof(*dag)); + dag->parents = &dag->parent_list; + list_init(dag->parents); + dag->instance_id = instance_id; + dag->def_route = NULL; + dag->rank = INFINITE_RANK; + dag->min_rank = INFINITE_RANK; + return dag; } } return NULL; @@ -254,7 +256,7 @@ rpl_free_dag(rpl_dag_t *dag) rpl_remove_routes(dag); /* Remove parents and the default route. */ - remove_parents(dag, NULL, !POISON_ROUTES); + remove_parents(dag, 0, !POISON_ROUTES); rpl_set_default_route(dag, NULL); ctimer_stop(&dag->dio_timer); @@ -276,15 +278,12 @@ rpl_add_parent(rpl_dag_t *dag, rpl_dio_t *dio, uip_ipaddr_t *addr) memcpy(&p->addr, addr, sizeof(p->addr)); p->dag = dag; - p->rank = dio->dag_rank; + p->rank = dio->rank; p->local_confidence = 0; p->dtsn = 0; list_add(dag->parents, p); - /* Draw a line between the node and its parent in Cooja. */ - ANNOTATE("#L %u 1\n", addr->u8[sizeof(*addr) - 1]); - return p; } /************************************************************************/ @@ -304,7 +303,7 @@ rpl_find_parent(rpl_dag_t *dag, uip_ipaddr_t *addr) /************************************************************************/ rpl_parent_t * -rpl_preferred_parent(rpl_dag_t *dag) +rpl_select_parent(rpl_dag_t *dag) { rpl_parent_t *p; rpl_parent_t *best; @@ -317,12 +316,32 @@ rpl_preferred_parent(rpl_dag_t *dag) best = dag->of->best_parent(best, p); } } - if(dag->best_parent != best) { - dag->best_parent = best; /* Cache the value. */ + + if(dag->preferred_parent != best) { + + /* Visualize the change of the preferred parent in Cooja. */ + ANNOTATE("#L %u 0\n", + dag->preferred_parent->addr.u8[sizeof(best->addr) - 1]); + ANNOTATE("#L %u 1\n", best->addr.u8[sizeof(best->addr) - 1]); + + dag->preferred_parent = best; /* Cache the value. */ rpl_set_default_route(dag, &best->addr); /* The DAO parent set changed - schedule a DAO transmission. */ rpl_schedule_dao(dag); + 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(best->rank < dag->min_rank) { + dag->min_rank = best->rank; + } else if(!acceptable_rank(dag, best->rank)) { + remove_parents(dag, 0, POISON_ROUTES); + return NULL; + } + return best; } /************************************************************************/ @@ -331,9 +350,6 @@ rpl_remove_parent(rpl_dag_t *dag, rpl_parent_t *parent) { uip_ds6_defrt_t *defrt; - ANNOTATE("#L %u 0\n", - parent->addr.u8[sizeof(parent->addr) - 1]); - /* Remove uIPv6 routes that have this parent as the next hop. **/ uip_ds6_route_rm_by_nexthop(&parent->addr); defrt = uip_ds6_defrt_lookup(&parent->addr); @@ -436,10 +452,11 @@ join_dag(uip_ipaddr_t *from, rpl_dio_t *dio) dag->preference = dio->preference; dag->grounded = dio->grounded; dag->instance_id = dio->instance_id; - dag->rank = dag->of->increment_rank(dio->dag_rank, p); + dag->rank = dag->of->calculate_rank(NULL, dio->rank); dag->min_rank = dag->rank; /* So far this is the lowest rank we know */ dag->version = dio->version; - dag->best_parent = p; + dag->preferred_parent = p; + ANNOTATE("#L %u 1\n", p->addr.u8[sizeof(p->addr) - 1]); dag->dio_intdoubl = dio->dag_intdoubl; dag->dio_intmin = dio->dag_intmin; @@ -473,7 +490,7 @@ global_repair(uip_ipaddr_t *from, rpl_dag_t *dag, rpl_dio_t *dio) { rpl_parent_t *p; - remove_parents(dag, NULL, !POISON_ROUTES); + remove_parents(dag, 0, !POISON_ROUTES); dag->version = dio->version; dag->dtsn_out = 1; dag->of->reset(dag); @@ -482,7 +499,8 @@ global_repair(uip_ipaddr_t *from, rpl_dag_t *dag, rpl_dio_t *dio) dag->rank = INFINITE_RANK; } else { rpl_set_default_route(dag, from); - dag->rank = dag->of->increment_rank(dio->dag_rank, p); + dag->rank = dag->of->calculate_rank(NULL, dio->rank); + dag->min_rank = dag->rank; rpl_reset_dio_timer(dag, 1); if(should_send_dao(dag, dio, p)) { rpl_schedule_dao(dag); @@ -506,18 +524,82 @@ rpl_repair_dag(rpl_dag_t *dag) } /************************************************************************/ void +rpl_recalculate_ranks(void) +{ + rpl_dag_t *dag; + rpl_parent_t *p; + + /* + * We recalculate ranks when we receive feedback from the system rather + * than RPL protocol messages. This periodical recalculation is called + * from a timer in order to keep the stack depth reasonably low. + */ + dag = rpl_get_dag(RPL_ANY_INSTANCE); + if(dag != NULL) { + for(p = list_head(dag->parents); p != NULL; p = p->next) { + if(p->updated) { + p->updated = 0; + rpl_process_parent_event(dag, p); + /* + * Stop calculating here because the parent list may have changed. + * If more ranks need to be recalculated, it will be taken care of + * in subsequent calls to this functions. + */ + break; + } + } + } +} +/************************************************************************/ +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 more parents, triggering a local repair\n"); + dag->rank = INFINITE_RANK; + rpl_reset_dio_timer(dag, 1); + return 1; + } + + if(old_rank != dag->rank) { + if(dag->rank < dag->min_rank) { + dag->min_rank = dag->rank; + } + PRINTF("RPL: Moving in the DAG from rank %hu to %hu\n", + old_rank, dag->rank); + PRINTF("RPL: The new preferred parent is "); + PRINT6ADDR(&dag->preferred_parent->addr); + PRINTF(" (rank %u)\n", (unsigned)(dag->preferred_parent->rank)); + rpl_reset_dio_timer(dag, 1); + } + + if(!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; +} +/************************************************************************/ +void rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) { rpl_dag_t *dag; rpl_parent_t *p; - rpl_parent_t *preferred_parent; - rpl_rank_t new_rank; - uint8_t new_parent; dag = rpl_get_dag(dio->instance_id); if(dag == NULL) { - /* Always join the first possible DAG that is not of INF_RANK. */ - if(dio->dag_rank != INFINITE_RANK) { + /* Join the first possible DAG of this RPL instance. */ + if(dio->rank != INFINITE_RANK) { join_dag(from, dio); } else { PRINTF("RPL: Ignoring DIO from node with infinite rank: "); @@ -527,12 +609,6 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) return; } - if(dag->instance_id != dio->instance_id) { - /* We avoid joining more than one RPL instance. */ - PRINTF("RPL: Cannot join another RPL instance\n"); - return; - } - if(memcmp(&dag->dag_id, &dio->dag_id, sizeof(dag->dag_id))) { PRINTF("RPL: Ignoring DIO for another DAG within our instance\n"); return; @@ -554,107 +630,57 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) return; } - /* This DIO pertains to a DAG that we are already part of. */ + if(dag->rank == ROOT_RANK) { + return; + } + + if(dio->rank == INFINITE_RANK) { + rpl_reset_dio_timer(dag, 1); + return; + } + + /* At this point, we know that this DIO pertains to a DAG that + we are already part of. */ + p = rpl_find_parent(dag, from); - if(p != NULL) { - if(should_send_dao(dag, dio, p)) { - rpl_schedule_dao(dag); + if(p == NULL) { + if(RPL_PARENT_COUNT(dag) == RPL_MAX_PARENTS && dio->rank >= dag->rank) { + /* Try to make room for a new parent. */ + remove_parents(dag, dio->rank, !POISON_ROUTES); } - p->dtsn = dio->dtsn; - if(p->rank > dio->dag_rank) { - p->rank = dio->dag_rank; - rpl_reset_dio_timer(dag, 1); - } else if(p->rank < dio->dag_rank) { - PRINTF("RPL: Existing parent "); - PRINT6ADDR(from); - PRINTF(" got a higher rank (%hu -> %hu)\n", - p->rank, dio->dag_rank); - p->rank = dio->dag_rank; - if(RPL_PARENT_COUNT(dag) > 1) { - /* Since we have alternative parents, we can simply drop this one. */ - rpl_remove_parent(dag, p); - p = rpl_preferred_parent(dag); - if(p != NULL) { - rpl_set_default_route(dag, &p->addr); - } - return; - } else if(dag->of->increment_rank(dio->dag_rank, p) <= dag->min_rank + dag->max_rankinc) { - preferred_parent = rpl_preferred_parent(dag); - if(p == preferred_parent) { - new_rank = dag->of->increment_rank(dio->dag_rank, p); - rpl_set_default_route(dag, &p->addr); - dag->rank = new_rank; - PRINTF("RPL: New rank is %hu, max is %hu\n", - dag->rank, dag->min_rank + dag->max_rankinc); - } - } else { - PRINTF("RPL: Cannot find an acceptable preferred parent\n"); - /* do local repair - jump down the DAG */ - remove_parents(dag, NULL, POISON_ROUTES); - dag->rank = INFINITE_RANK; - } - rpl_reset_dio_timer(dag, 1); - } else { - /* Assume consistency and increase the DIO counter. */ - PRINTF("RPL: Received a consistent DIO\n"); - dag->dio_counter++; - } - } - - if(dio->dag_rank < dag->rank) { - /* Message from a node closer to the root, but we might still be out of allowed rank-range */ - if(dag->max_rankinc > 0 && dag->min_rank + dag->max_rankinc < - dag->of->increment_rank(dio->dag_rank, NULL)) { - PRINTF("RPL: Could not add parent, resulting rank too high\n"); - return; - } - new_parent = 0; + /* Add the DIO sender as a candidate parent. */ + p = rpl_add_parent(dag, dio, from); if(p == NULL) { - p = rpl_add_parent(dag, dio, from); - if(p == NULL) { - PRINTF("RPL: Could not add parent\n"); - return; - } - - PRINTF("RPL: New parent with rank %hu: ", p->rank); + PRINTF("RPL: Failed to add a new parent ("); PRINT6ADDR(from); - PRINTF("\n"); - new_parent = 1; + PRINTF(")\n"); + return; } - new_rank = dag->of->increment_rank(dio->dag_rank, p); - if(new_rank < dag->rank) { - PRINTF("RPL: Moving up within the DAG from rank %hu to %hu\n", - dag->rank, new_rank); - dag->rank = new_rank; - dag->min_rank = new_rank; /* So far this is the lowest rank we know */ - rpl_reset_dio_timer(dag, 1); - - /* Remove old def-route and add the new */ - /* fix handling of destination prefix */ - rpl_set_default_route(dag, from); - - if(new_parent) { - remove_parents(dag, p, POISON_ROUTES); - } - } - } else if(dio->dag_rank == dag->rank) { - /* Message from a sibling. */ - } else { - /* Message from a node at a longer distance from the root. If the - node is in the parent list, we just remove it. */ - if(p != NULL && p->rank < dio->dag_rank) { - PRINTF("RPL: Parent "); - PRINT6ADDR(&p->addr); - PRINTF(" has increased in rank from %hu to %hu. Removing it.\n", - p->rank, dio->dag_rank); - rpl_remove_parent(dag, p); - if(RPL_PARENT_COUNT(dag) == 0) { - dag->rank = INFINITE_RANK; - } - } + PRINTF("RPL: New candidate parent with rank %u: ", (unsigned)p->rank); + PRINT6ADDR(from); + PRINTF("\n"); } + + /* We have an allocated candidate parent, process the DIO further. */ + + if(p->rank != dio->rank) { + p->rank = dio->rank; + if(rpl_process_parent_event(dag, p) == 0) { + /* The candidate parent no longer exists. */ + return; + } + printf("X1.2\n"); + } else { + PRINTF("RPL: Received consistent DIO\n"); + dag->dio_counter++; + } + + if(should_send_dao(dag, dio, p)) { + rpl_schedule_dao(dag); + } + p->dtsn = dio->dtsn; } /************************************************************************/ void @@ -662,51 +688,17 @@ rpl_ds6_neighbor_callback(uip_ds6_nbr_t *nbr) { rpl_dag_t *dag; rpl_parent_t *p; - rpl_parent_t *new_p; - - if(nbr->isused) { - PRINTF("RPL: Neighbor state %u: ", nbr->state); - PRINT6ADDR(&nbr->ipaddr); - PRINTF("\n"); - return; - } - - PRINTF("RPL: Removing neighbor "); - PRINT6ADDR(&nbr->ipaddr); - PRINTF("\n"); dag = rpl_get_dag(RPL_ANY_INSTANCE); - if(dag == NULL) { - return; - } - - p = rpl_find_parent(dag, &nbr->ipaddr); - if(p != NULL) { - if(p == dag->best_parent) { - /* Try to select a new preferred parent. */ - new_p = rpl_preferred_parent(dag); - if(new_p == NULL) { - rpl_free_dag(dag); - return; - } - - if(acceptable_rank_increase(dag, new_p)) { - dag->rank = dag->of->increment_rank(new_p->rank, new_p); - if(dag->rank < dag->min_rank) { - dag->min_rank = dag->rank; - } - PRINTF("RPL: New rank is %hu, max is %hu\n", - dag->rank, dag->min_rank + dag->max_rankinc); - rpl_set_default_route(dag, &new_p->addr); - } else { - PRINTF("RPL: Cannot select the preferred parent\n"); - /* do local repair - jump down the DAG */ - rpl_set_default_route(dag, NULL); - remove_parents(dag, NULL, POISON_ROUTES); - dag->rank = INFINITE_RANK; - rpl_reset_dio_timer(dag, 1); - } + if(!nbr->isused && dag) { + PRINTF("RPL: Removing neighbor "); + PRINT6ADDR(&nbr->ipaddr); + PRINTF("\n"); + p = rpl_find_parent(dag, &nbr->ipaddr); + if(p != NULL) { + p->rank = INFINITE_RANK; + /* Trigger DAG rank recalculation. */ + p->updated = 1; } - rpl_remove_parent(dag, p); } } diff --git a/core/net/rpl/rpl-icmp6.c b/core/net/rpl/rpl-icmp6.c index 9f75e0e29..53c3a261c 100644 --- a/core/net/rpl/rpl-icmp6.c +++ b/core/net/rpl/rpl-icmp6.c @@ -33,7 +33,7 @@ * * This file is part of the Contiki operating system. * - * $Id: rpl-icmp6.c,v 1.20 2010/06/12 10:55:46 joxe Exp $ + * $Id: rpl-icmp6.c,v 1.21 2010/06/14 12:44:37 nvt-se Exp $ */ /** * \file @@ -203,7 +203,6 @@ dio_input(void) PRINTF("RPL: Neighbor already in neighbor cache\n"); } - buffer_length = uip_len - uip_l2_l3_icmp_hdr_len; /* Process the DIO base option. */ @@ -212,9 +211,11 @@ dio_input(void) dio.instance_id = buffer[i++]; dio.version = buffer[i++]; - dio.dag_rank = (buffer[i] << 8) + buffer[i + 1]; + dio.rank = (buffer[i] << 8) + buffer[i + 1]; i += 2; + PRINTF("RPL: Incoming DIO rank %u\n", (unsigned)dio.rank); + dio.grounded = buffer[i] & RPL_DIO_GROUNDED; dio.dst_adv_trigger = buffer[i] & RPL_DIO_DEST_ADV_TRIGGER; dio.dst_adv_supported = buffer[i] & RPL_DIO_DEST_ADV_SUPPORTED; @@ -304,7 +305,6 @@ dio_output(rpl_dag_t *dag, uip_ipaddr_t *uc_addr) uip_ipaddr_t addr; /* DAG Information Solicitation */ - PRINTF("RPL: Sending a DIO with rank: %u\n", (unsigned)dag->rank); pos = 0; buffer = UIP_ICMP_PAYLOAD; @@ -354,13 +354,13 @@ dio_output(rpl_dag_t *dag, uip_ipaddr_t *uc_addr) pos += 4; memset(&buffer[pos], 0, 4); pos += 4; - memcpy(&buffer[pos], &(dag->prefix_info.prefix), 16); + memcpy(&buffer[pos], &dag->prefix_info.prefix, 16); pos += 16; - PRINTF("RPL: Sending prefix info in DIO "); + PRINTF("RPL: Sending prefix info in DIO for "); PRINT6ADDR(&dag->prefix_info.prefix); PRINTF("\n"); } else { - PRINTF("RPL: No prefix to announce. len:%d\n", + PRINTF("RPL: No prefix to announce (len %d)\n", dag->prefix_info.length); } @@ -395,7 +395,6 @@ dao_input(void) uint8_t subopt_type; uip_ipaddr_t prefix; uip_ds6_route_t *rep; - rpl_parent_t *n; uint8_t buffer_length; int pos; int len; @@ -417,6 +416,14 @@ dao_input(void) pos = 0; instance_id = buffer[pos++]; + + dag = rpl_get_dag(instance_id); + if(dag == NULL) { + PRINTF("RPL: Ignoring a DAO for a different RPL instance (%u)\n", + instance_id); + return; + } + flags = buffer[pos++]; /* reserved */ pos++; @@ -429,14 +436,6 @@ dao_input(void) pos += 16; } - /* handle the target option */ - dag = rpl_get_dag(instance_id); - if(dag == NULL) { - PRINTF("RPL: Ignoring a DAO for a different RPL instance (%u)\n", - instance_id); - return; - } - /* Check if there are any DIO suboptions. */ i = pos; for(; i < buffer_length; i += len) { @@ -450,6 +449,7 @@ dao_input(void) switch(subopt_type) { case RPL_DIO_SUBOPT_TARGET: + /* handle the target option */ prefixlen = buffer[i + 3]; memset(&prefix, 0, sizeof(prefix)); memcpy(&prefix, buffer + i + 4, (prefixlen + 7) / CHAR_BIT); @@ -493,11 +493,12 @@ dao_input(void) } if(learned_from == RPL_ROUTE_FROM_UNICAST_DAO) { - if((n = rpl_preferred_parent(dag)) != NULL) { + if(dag->preferred_parent) { PRINTF("RPL: Forwarding DAO to parent "); - PRINT6ADDR(&n->addr); + PRINT6ADDR(&dag->preferred_parent->addr); PRINTF("\n"); - uip_icmp6_send(&n->addr, ICMP6_RPL, RPL_CODE_DAO, buffer_length); + uip_icmp6_send(&dag->preferred_parent->addr, + ICMP6_RPL, RPL_CODE_DAO, buffer_length); } else if(flags & RPL_DAO_K_FLAG) { dao_ack_output(dag, &dao_sender_addr, sequence); } @@ -536,7 +537,11 @@ dao_output(rpl_parent_t *n, uint32_t lifetime) pos = 0; buffer[pos++] = dag->instance_id; - buffer[pos++] = RPL_DAO_K_FLAG; /* no ack request, no DODAGID */ +#if RPL_CONF_DAO_ACK + buffer[pos++] = RPL_DAO_K_FLAG; /* DAO ACK request, no DODAGID */ +#else + buffer[pos++] = 0; /* No DAO ACK request, no DODAGID */ +#endif buffer[pos++] = 0; /* reserved */ buffer[pos++] = dao_sequence & 0xff; diff --git a/core/net/rpl/rpl-of-etx.c b/core/net/rpl/rpl-of-etx.c index 054e29a61..139d6532b 100644 --- a/core/net/rpl/rpl-of-etx.c +++ b/core/net/rpl/rpl-of-etx.c @@ -32,7 +32,7 @@ * * This file is part of the Contiki operating system. * - * $Id: rpl-of-etx.c,v 1.4 2010/06/03 12:12:20 nvt-se Exp $ + * $Id: rpl-of-etx.c,v 1.5 2010/06/14 12:44:37 nvt-se Exp $ */ /** * \file @@ -49,18 +49,19 @@ static void reset(void *); static void parent_state_callback(rpl_parent_t *, int, int); static rpl_parent_t *best_parent(rpl_parent_t *, rpl_parent_t *); -static rpl_rank_t increment_rank(rpl_rank_t, rpl_parent_t *); +static rpl_rank_t calculate_rank(rpl_parent_t *, rpl_rank_t); rpl_of_t rpl_of_etx = { reset, parent_state_callback, best_parent, - increment_rank, + calculate_rank, 1 }; #define LINK_ETX_MIN 1 #define LINK_ETX_MAX 10 +#define LINK_ETX_GUESS (LINK_ETX_MAX - 1) #define PATH_ETX_MIN 1 #define PATH_ETX_MAX 200 #define PARENT_SWITCH_ETX_THRESHOLD 0.5 @@ -82,13 +83,7 @@ parent_state_callback(rpl_parent_t *parent, int known, int etx) dag = (rpl_dag_t *)parent->dag; - if(known) { - if(min_path_etx != INFINITE_RANK) { - dag->rank = min_path_etx + etx; - PRINTF("RPL: New path ETX: %u min_path_etx=%u etx=%u\n", - (unsigned)(min_path_etx + etx), min_path_etx, etx); - } - } else { + if(!known) { if(RPL_PARENT_COUNT(dag) == 1) { /* Our last parent has disappeared, set the path ETX to INFINITE_RANK. */ min_path_etx = INFINITE_RANK; @@ -97,24 +92,38 @@ parent_state_callback(rpl_parent_t *parent, int known, int etx) } static rpl_rank_t -increment_rank(rpl_rank_t rank, rpl_parent_t *parent) +calculate_rank(rpl_parent_t *p, rpl_rank_t base_rank) { + rpl_dag_t *dag; rpl_rank_t new_rank; + rpl_rank_t rank_increase; - PRINTF("RPL: OF1 increment rank\n"); + PRINTF("RPL: OF1 calculate rank\n"); - if(parent != NULL && parent->rank < min_path_etx) { - min_path_etx = parent->rank; - PRINTF("RPL: min_path_etx updated to:%u\n", min_path_etx); + dag = (rpl_dag_t *)p->dag; + + rank_increase = p == NULL ? LINK_ETX_GUESS : p->local_confidence; + rank_increase += dag->min_hoprankinc; + + if(base_rank == 0) { + if(p == NULL) { + return INFINITE_RANK; + } + base_rank = p->rank; } - if(INFINITE_RANK - rank < LINK_ETX_MAX) { + if(base_rank < min_path_etx) { + min_path_etx = base_rank; + PRINTF("RPL: min_path_etx updated to %u\n", min_path_etx); + } + + if(INFINITE_RANK - base_rank < rank_increase) { /* Reached the maximum rank. */ new_rank = INFINITE_RANK; } else { /* Calculate the rank based on the new rank information from DIO or stored otherwise. */ - new_rank = rank + LINK_ETX_MAX; + new_rank = base_rank + rank_increase; } PRINTF("RPL: Path ETX %u\n", (unsigned)new_rank); @@ -125,7 +134,24 @@ increment_rank(rpl_rank_t rank, rpl_parent_t *parent) static rpl_parent_t * best_parent(rpl_parent_t *p1, rpl_parent_t *p2) { - if(p1->rank < p2->rank) { + rpl_dag_t *dag; + rpl_rank_t p1_rank; + rpl_rank_t p2_rank; + + p1_rank = calculate_rank(p1, 0); + p2_rank = calculate_rank(p2, 0); + + /* Maintain stability of the preferred parent in case of similar ranks. */ + if(p1_rank == p2_rank) { + dag = (rpl_dag_t *)p1->dag; + if(p1 == dag->preferred_parent) { + return p1; + } else if(p2 == dag->preferred_parent) { + return p2; + } + } + + if(p1_rank < p2_rank) { return p1; } diff --git a/core/net/rpl/rpl-of0.c b/core/net/rpl/rpl-of0.c index 0cf795d14..e490d9d4d 100644 --- a/core/net/rpl/rpl-of0.c +++ b/core/net/rpl/rpl-of0.c @@ -32,7 +32,7 @@ * * This file is part of the Contiki operating system. * - * $Id: rpl-of0.c,v 1.4 2010/05/31 14:22:00 nvt-se Exp $ + * $Id: rpl-of0.c,v 1.5 2010/06/14 12:44:37 nvt-se Exp $ */ /** * \file @@ -48,13 +48,13 @@ static void reset(void *); static rpl_parent_t *best_parent(rpl_parent_t *, rpl_parent_t *); -static rpl_rank_t increment_rank(rpl_rank_t, rpl_parent_t *); +static rpl_rank_t calculate_rank(rpl_parent_t *, rpl_rank_t); rpl_of_t rpl_of0 = { reset, NULL, best_parent, - increment_rank, + calculate_rank, 0 }; @@ -70,14 +70,21 @@ reset(void *dag) } static rpl_rank_t -increment_rank(rpl_rank_t rank, rpl_parent_t *parent) +calculate_rank(rpl_parent_t *p, rpl_rank_t base_rank) { - if((rpl_rank_t)(rank + DEFAULT_RANK_INCREMENT) < rank) { + if(base_rank == 0) { + if(p == NULL) { + return INFINITE_RANK; + } + base_rank = p->rank; + } + + if((rpl_rank_t)(base_rank + DEFAULT_RANK_INCREMENT) < base_rank) { PRINTF("RPL: OF0 rank %d incremented to infinite rank due to wrapping\n", - rank); + base_rank); return INFINITE_RANK; } - return rank + DEFAULT_RANK_INCREMENT; + return base_rank + DEFAULT_RANK_INCREMENT; } static rpl_parent_t * @@ -91,15 +98,17 @@ best_parent(rpl_parent_t *p1, rpl_parent_t *p2) PRINTF(" (confidence %d, rank %d)\n", p2->local_confidence, p2->rank); + if(p1->rank < p2->rank) { + return p1; + } else if(p2->rank < p1->rank) { + return p2; + } + if(p1->local_confidence > p2->local_confidence) { return p1; } else if(p2->local_confidence > p1->local_confidence) { return p2; } - if(p1->rank < p2->rank) { - return p1; - } - return p2; } diff --git a/core/net/rpl/rpl-timers.c b/core/net/rpl/rpl-timers.c index 1302cb441..bc7ed1527 100644 --- a/core/net/rpl/rpl-timers.c +++ b/core/net/rpl/rpl-timers.c @@ -32,7 +32,7 @@ * * This file is part of the Contiki operating system. * - * $Id: rpl-timers.c,v 1.9 2010/06/14 11:35:21 adamdunkels Exp $ + * $Id: rpl-timers.c,v 1.10 2010/06/14 12:44:37 nvt-se Exp $ */ /** * \file @@ -42,9 +42,9 @@ */ #include "contiki-conf.h" -#include "sys/ctimer.h" #include "net/rpl/rpl.h" #include "lib/random.h" +#include "sys/ctimer.h" #define DEBUG DEBUG_ANNOTATE #include "net/uip-debug.h" @@ -66,6 +66,7 @@ static void handle_periodic_timer(void *ptr) { rpl_purge_routes(); + rpl_recalculate_ranks(); /* handle DIS */ #ifdef RPL_DIS_SEND @@ -84,7 +85,7 @@ new_dio_interval(rpl_dag_t *dag) unsigned long time; /* TODO: too small timer intervals for many cases */ - time = 1L << dag->dio_intcurrent; + time = 1UL << dag->dio_intcurrent; /* need to convert from milliseconds to CLOCK_TICKS */ time = (time * CLOCK_SECOND) / 1000; @@ -128,7 +129,7 @@ handle_dio_timer(void *ptr) if(uip_ds6_get_link_local(ADDR_PREFERRED) != NULL) { dio_send_ok = 1; } else { - PRINTF("RPL: Postponing DIO transmission since link local addres is not ok\n"); + PRINTF("RPL: Postponing DIO transmission since link local address is not ok\n"); ctimer_set(&dag->dio_timer, CLOCK_SECOND, &handle_dio_timer, dag); return; } @@ -166,7 +167,7 @@ rpl_reset_periodic_timer(void) ctimer_set(&periodic_timer, CLOCK_SECOND, handle_periodic_timer, NULL); } /************************************************************************/ -/* Resets the DIO timer in the DAG and starts-up the interval */ +/* Resets the DIO timer in the DAG to its minimal interval. */ void rpl_reset_dio_timer(rpl_dag_t *dag, uint8_t force) { @@ -182,7 +183,6 @@ static void handle_dao_timer(void *ptr) { rpl_dag_t *dag; - rpl_parent_t *n; dag = (rpl_dag_t *)ptr; @@ -194,10 +194,9 @@ handle_dao_timer(void *ptr) /* Send the DAO to the best parent. rpl-07 section C.2 lists the fan-out as being under investigation. */ - n = rpl_preferred_parent(dag); - if(n != NULL) { + if(dag->preferred_parent != NULL) { PRINTF("RPL: handle_dao_timer - sending DAO\n"); - dao_output(n, DEFAULT_ROUTE_LIFETIME); + dao_output(dag->preferred_parent, DEFAULT_ROUTE_LIFETIME); } else { PRINTF("RPL: Could not find a parent to send a DAO to \n"); } diff --git a/core/net/rpl/rpl.c b/core/net/rpl/rpl.c index 35f63addb..04042f925 100644 --- a/core/net/rpl/rpl.c +++ b/core/net/rpl/rpl.c @@ -32,7 +32,7 @@ * * This file is part of the Contiki operating system. * - * $Id: rpl.c,v 1.6 2010/06/03 15:20:56 nvt-se Exp $ + * $Id: rpl.c,v 1.7 2010/06/14 12:44:37 nvt-se Exp $ */ /** * \file @@ -53,12 +53,6 @@ #include /************************************************************************/ -#ifndef RPL_CONF_MAX_ROUTE_ENTRIES -#define RPL_MAX_ROUTE_ENTRIES 10 -#else -#define RPL_MAX_ROUTE_ENTRIES RPL_CONF_MAX_ROUTE_ENTRIES -#endif /* !RPL_CONF_MAX_ROUTE_ENTRIES */ - extern uip_ds6_route_t uip_ds6_routing_table[UIP_DS6_ROUTE_NB]; /************************************************************************/ void @@ -151,6 +145,12 @@ neighbor_callback(const rimeaddr_t *addr, int known, int etx) return; } + if(etx != parent->local_confidence) { + /* Trigger DAG rank recalculation. */ + parent->updated = 1; + } + parent->local_confidence = etx; + if(dag->of->parent_state_callback != NULL) { dag->of->parent_state_callback(parent, known, etx); } @@ -159,28 +159,8 @@ neighbor_callback(const rimeaddr_t *addr, int known, int etx) PRINTF("RPL: Removing parent "); PRINT6ADDR(&parent->addr); PRINTF(" because of bad connectivity (ETX %d)\n", etx); - rpl_remove_parent(dag, parent); - if(RPL_PARENT_COUNT(dag) == 0) { - rpl_free_dag(dag); - } else { - /* Select a new default route. */ - parent = rpl_preferred_parent(dag); - if(parent != NULL) { - PRINTF("RPL: Switching preferred parent to "); - PRINT6ADDR(&parent->addr); - PRINTF("\n"); - rpl_set_default_route(dag, &parent->addr); - } - } - } else { - parent->local_confidence = ~0 - etx; - PRINTF("RPL: Updating the local confidence value for this parent to %d\n", - parent->local_confidence); - if(parent != dag->best_parent && - dag->of->best_parent(parent, dag->best_parent) == parent) { - dag->best_parent = parent; - rpl_set_default_route(dag, &parent->addr); - } + parent->rank = INFINITE_RANK; + parent->updated = 1; } } /************************************************************************/ diff --git a/core/net/rpl/rpl.h b/core/net/rpl/rpl.h index dd9d63981..895432768 100644 --- a/core/net/rpl/rpl.h +++ b/core/net/rpl/rpl.h @@ -30,7 +30,7 @@ * * Author: Joakim Eriksson, Nicolas Tsiftes * - * $Id: rpl.h,v 1.18 2010/06/14 11:33:58 adamdunkels Exp $ + * $Id: rpl.h,v 1.19 2010/06/14 12:44:37 nvt-se Exp $ */ #ifndef RPL_H @@ -110,7 +110,7 @@ #define RPL_DEFAULT_OCP 1 /* TODO: pick these from OCP later? */ -#define DEFAULT_MAX_RANKINC 16 +#define DEFAULT_MAX_RANKINC 10 #define DEFAULT_MIN_HOPRANKINC 4 /* Represents 2^n ms. */ @@ -120,7 +120,7 @@ #define DEFAULT_DIO_INTERVAL_DOUBLINGS 8 /* Desired DIO redundancy. */ -#define DEFAULT_DIO_REDUNDANCY 1 +#define DEFAULT_DIO_REDUNDANCY 5 /* Expire DAOs from neighbors that do not respond in this time. (seconds) */ #define DAO_EXPIRATION_TIMEOUT 60 @@ -158,25 +158,47 @@ struct rpl_parent { rpl_rank_t rank; uint8_t local_confidence; uint8_t dtsn; + uint8_t updated; }; typedef struct rpl_parent rpl_parent_t; +/*---------------------------------------------------------------------------*/ +/* + * API for RPL objective functions (OF) + * + * reset(dag) + * + * Resets the objective function state for a specific DAG. This function is + * called when doing a global repair on the DAG. + * + * parent_state_callback(parent, known, etx) + * + * Receives link-layer neighbor information. The parameter "known" is set + * either to 0 or 1. The "etx" parameter specifies the current + * ETX(estimated transmissions) for the neighbor. + * + * best_parent(parent1, parent2) + * + * Compares two parents and returns the best one, according to the OF. + * + * calculate_rank(parent, base_rank) + * + * Calculates a rank value using the parent rank and a base rank. + * If "parent" is NULL, the objective function selects a default increment + * that is adds to the "base_rank". Otherwise, the OF uses information known + * about "parent" to select an increment to the "base_rank". + */ struct rpl_of { void (*reset)(void *); void (*parent_state_callback)(rpl_parent_t *, int, int); rpl_parent_t *(*best_parent)(rpl_parent_t *, rpl_parent_t *); - - /* Increment the rank - the rank that just have been received in a DIO - (or if picked from a parent) is the first argument. This is considered - the valid rank to calculate based on. The second argument is the parent - that is related to this calculation - if any (can be NULL) */ - rpl_rank_t (*increment_rank)(rpl_rank_t rank, rpl_parent_t *parent); + rpl_rank_t (*calculate_rank)(rpl_parent_t *, rpl_rank_t); rpl_ocp_t ocp; }; - typedef struct rpl_of rpl_of_t; +/*---------------------------------------------------------------------------*/ /* RPL DIO prefix suboption */ struct rpl_prefix { @@ -192,7 +214,7 @@ typedef struct rpl_prefix rpl_prefix_t; struct rpl_dio { uip_ipaddr_t dag_id; rpl_ocp_t ocp; - rpl_rank_t dag_rank; + rpl_rank_t rank; uint8_t grounded; uint8_t dst_adv_trigger; uint8_t dst_adv_supported; @@ -216,7 +238,7 @@ struct rpl_dag { /* DAG configuration */ rpl_of_t *of; uip_ipaddr_t dag_id; - /* this is the current def-router that is set - used for routing "upwards" */ + /* The current default router - used for routing "upwards" */ uip_ds6_defrt_t *def_route; rpl_rank_t rank; rpl_rank_t min_rank; /* should be reset per DODAG iteration! */ @@ -245,7 +267,7 @@ struct rpl_dag { uint16_t dio_next_delay; /* delay for completion of dio interval */ struct ctimer dio_timer; struct ctimer dao_timer; - rpl_parent_t *best_parent; + rpl_parent_t *preferred_parent; void *parent_list; list_t parents; rpl_prefix_t prefix_info; @@ -254,7 +276,7 @@ struct rpl_dag { typedef struct rpl_dag rpl_dag_t; /*---------------------------------------------------------------------------*/ -/* RPL macro functions. */ +/* RPL macros. */ #define RPL_PARENT_COUNT(dag) list_length((dag)->parents) /*---------------------------------------------------------------------------*/ /* ICMPv6 functions for RPL. */ @@ -270,6 +292,7 @@ int rpl_set_prefix(rpl_dag_t *dag, uip_ipaddr_t *prefix, int len); int rpl_repair_dag(rpl_dag_t *dag); int rpl_set_default_route(rpl_dag_t *dag, uip_ipaddr_t *from); void rpl_process_dio(uip_ipaddr_t *, rpl_dio_t *); +int rpl_process_parent_event(rpl_dag_t *, rpl_parent_t *); /* DAG allocation and deallocation. */ rpl_dag_t *rpl_alloc_dag(uint8_t); @@ -279,7 +302,8 @@ void rpl_free_dag(rpl_dag_t *); rpl_parent_t *rpl_add_parent(rpl_dag_t *, rpl_dio_t *dio, uip_ipaddr_t *); rpl_parent_t *rpl_find_parent(rpl_dag_t *, uip_ipaddr_t *); int rpl_remove_parent(rpl_dag_t *, rpl_parent_t *); -rpl_parent_t *rpl_preferred_parent(rpl_dag_t *dag); +rpl_parent_t *rpl_select_parent(rpl_dag_t *dag); +void rpl_recalculate_ranks(void); void rpl_join_dag(rpl_dag_t *); rpl_dag_t *rpl_get_dag(int instance_id);