Make RPL use neighbor tables. RPL locks the neighbor used as preferred parent.

This commit is contained in:
Simon Duquennoy 2013-07-03 19:53:51 +02:00
parent 09d26f8060
commit c50d10aa53
5 changed files with 140 additions and 158 deletions

View file

@ -45,6 +45,7 @@
#include "net/rpl/rpl-private.h"
#include "net/uip.h"
#include "net/uip-nd6.h"
#include "net/neighbor-table.h"
#include "lib/list.h"
#include "lib/memb.h"
#include "sys/ctimer.h"
@ -62,13 +63,6 @@
extern rpl_of_t RPL_OF;
static rpl_of_t * const objective_functions[] = {&RPL_OF};
/*---------------------------------------------------------------------------*/
#ifndef RPL_CONF_MAX_PARENTS_PER_DAG
#define RPL_MAX_PARENTS_PER_DAG 8
#else
#define RPL_MAX_PARENTS_PER_DAG RPL_CONF_MAX_PARENTS_PER_DAG
#endif /* !RPL_CONF_MAX_PARENTS_PER_DAG */
/*---------------------------------------------------------------------------*/
/* RPL definitions. */
@ -79,14 +73,49 @@ static rpl_of_t * const objective_functions[] = {&RPL_OF};
#endif /* !RPL_CONF_GROUNDED */
/*---------------------------------------------------------------------------*/
/* Allocate parents from the same static MEMB chunk to reduce memory waste. */
MEMB(parent_memb, struct rpl_parent,
RPL_MAX_PARENTS_PER_DAG * RPL_MAX_INSTANCES * RPL_MAX_DAG_PER_INSTANCE);
/* Per-parent RPL information */
NEIGHBOR_TABLE(rpl_parent_t, rpl_parents);
/*---------------------------------------------------------------------------*/
/* Allocate instance table. */
rpl_instance_t instance_table[RPL_MAX_INSTANCES];
rpl_instance_t *default_instance;
/*---------------------------------------------------------------------------*/
void
rpl_dag_init()
{
nbr_table_register(rpl_parents, (remove_callback_func *)rpl_remove_parent);
}
/*---------------------------------------------------------------------------*/
rpl_rank_t
rpl_get_parent_rank(uip_lladdr_t *addr)
{
rpl_parent_t *p = nbr_table_get_from_lladdr(rpl_parents, (rimeaddr_t *)addr);
if(p != NULL) {
return p->rank;
} else {
return 0;
}
}
/*---------------------------------------------------------------------------*/
uip_ipaddr_t *
rpl_get_parent_ipaddr(rpl_parent_t *p)
{
rimeaddr_t *lladdr = nbr_table_get_lladdr(rpl_parents, p);
return uip_ds6_nbr_ipaddr_from_lladdr((uip_lladdr_t *)lladdr);
}
/*---------------------------------------------------------------------------*/
static void
rpl_set_preferred_parent(rpl_dag_t *dag, rpl_parent_t *p)
{
if(dag != NULL && dag->preferred_parent != p) {
/* Always keep the preferred parent locked, so it remains in the
* neighbor table. */
nbr_table_unlock(rpl_parents, dag->preferred_parent);
nbr_table_lock(rpl_parents, p);
}
dag->preferred_parent = p;
}
/*---------------------------------------------------------------------------*/
/* Greater-than function for the lollipop counter. */
/*---------------------------------------------------------------------------*/
static int
@ -107,53 +136,34 @@ lollipop_greater_than(int a, int b)
static void
remove_parents(rpl_dag_t *dag, rpl_rank_t minimum_rank)
{
rpl_parent_t *p, *p2;
rpl_parent_t *p;
PRINTF("RPL: Removing parents (minimum rank %u)\n",
minimum_rank);
for(p = list_head(dag->parents); p != NULL; p = p2) {
p2 = p->next;
if(p->rank >= minimum_rank) {
rpl_remove_parent(dag, p);
p = nbr_table_head(rpl_parents);
while(p != NULL) {
if(dag == p->dag && p->rank >= minimum_rank) {
rpl_remove_parent(p);
}
p = nbr_table_next(rpl_parents, p);
}
}
/*---------------------------------------------------------------------------*/
static void
nullify_parents(rpl_dag_t *dag, rpl_rank_t minimum_rank)
{
rpl_parent_t *p, *p2;
rpl_parent_t *p;
PRINTF("RPL: Removing parents (minimum rank %u)\n",
minimum_rank);
for(p = list_head(dag->parents); p != NULL; p = p2) {
p2 = p->next;
if(p->rank >= minimum_rank) {
rpl_nullify_parent(dag, p);
p = nbr_table_head(rpl_parents);
while(p != NULL) {
if(dag == p->dag && p->rank >= minimum_rank) {
rpl_nullify_parent(p);
}
}
}
/*---------------------------------------------------------------------------*/
static void
remove_worst_parent(rpl_dag_t *dag, rpl_rank_t min_worst_rank)
{
rpl_parent_t *p, *worst;
PRINTF("RPL: Removing the worst parent\n");
/* Find the parent with the highest rank. */
worst = NULL;
for(p = list_head(dag->parents); p != NULL; p = list_item_next(p)) {
if(p != dag->preferred_parent &&
(worst == NULL || p->rank > worst->rank)) {
worst = p;
}
}
/* Remove the neighbor if its rank is worse than the minimum worst rank. */
if(worst != NULL && worst->rank > min_worst_rank) {
rpl_remove_parent(dag, worst);
p = nbr_table_next(rpl_parents, p);
}
}
/*---------------------------------------------------------------------------*/
@ -231,7 +241,7 @@ rpl_set_root(uint8_t instance_id, uip_ipaddr_t *dag_id)
dag->grounded = RPL_GROUNDED;
instance->mop = RPL_MOP_DEFAULT;
instance->of = &RPL_OF;
dag->preferred_parent = NULL;
rpl_set_preferred_parent(dag, NULL);
memcpy(&dag->dag_id, dag_id, sizeof(dag->dag_id));
@ -430,7 +440,6 @@ rpl_alloc_dag(uint8_t instance_id, uip_ipaddr_t *dag_id)
for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DAG_PER_INSTANCE; dag < end; ++dag) {
if(!dag->used) {
memset(dag, 0, sizeof(*dag));
LIST_STRUCT_INIT(dag, parents);
dag->used = 1;
dag->rank = INFINITE_RANK;
dag->min_rank = INFINITE_RANK;
@ -502,18 +511,14 @@ rpl_free_dag(rpl_dag_t *dag)
rpl_parent_t *
rpl_add_parent(rpl_dag_t *dag, rpl_dio_t *dio, uip_ipaddr_t *addr)
{
rpl_parent_t *p;
rpl_parent_t *p = NULL;
/* Is the parent known by ds6? Drop this request if not.
* Typically, the parent is added upon receiving a DIO. */
uip_lladdr_t *lladdr = uip_ds6_nbr_lladdr_from_ipaddr(addr);
if(RPL_PARENT_COUNT(dag) == RPL_MAX_PARENTS_PER_DAG) {
return NULL;
}
p = memb_alloc(&parent_memb);
if(p == NULL) {
RPL_STAT(rpl_stats.mem_overflows++);
return NULL;
}
memcpy(&p->addr, addr, sizeof(p->addr));
if(lladdr != NULL) {
/* Add parent in rpl_parents */
p = nbr_table_add_lladdr(rpl_parents, (rimeaddr_t *)lladdr);
p->dag = dag;
p->rank = dio->rank;
p->dtsn = dio->dtsn;
@ -521,58 +526,50 @@ rpl_add_parent(rpl_dag_t *dag, rpl_dio_t *dio, uip_ipaddr_t *addr)
#if RPL_DAG_MC != RPL_DAG_MC_NONE
memcpy(&p->mc, &dio->mc, sizeof(p->mc));
#endif /* RPL_DAG_MC != RPL_DAG_MC_NONE */
list_add(dag->parents, p);
}
return p;
}
/*---------------------------------------------------------------------------*/
static rpl_parent_t *
find_parent_any_dag_any_instance(uip_ipaddr_t *addr)
{
uip_ds6_nbr_t *ds6_nbr = uip_ds6_nbr_lookup(addr);
uip_lladdr_t *lladdr = uip_ds6_nbr_get_ll(ds6_nbr);
return nbr_table_get_from_lladdr(rpl_parents, (rimeaddr_t *)lladdr);
}
/*---------------------------------------------------------------------------*/
rpl_parent_t *
rpl_find_parent(rpl_dag_t *dag, uip_ipaddr_t *addr)
{
rpl_parent_t *p;
for(p = list_head(dag->parents); p != NULL; p = p->next) {
if(uip_ipaddr_cmp(&p->addr, addr)) {
rpl_parent_t *p = find_parent_any_dag_any_instance(addr);
if(p != NULL && p->dag == dag) {
return p;
}
}
} else {
return NULL;
}
}
/*---------------------------------------------------------------------------*/
static rpl_dag_t *
find_parent_dag(rpl_instance_t *instance, uip_ipaddr_t *addr)
{
rpl_parent_t *p;
rpl_dag_t *dag, *end;
for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DAG_PER_INSTANCE; dag < end; ++dag) {
if(dag->used) {
for(p = list_head(dag->parents); p != NULL; p = p->next) {
if(uip_ipaddr_cmp(&p->addr, addr)) {
return dag;
}
}
}
}
rpl_parent_t *p = find_parent_any_dag_any_instance(addr);
if(p != NULL) {
return p->dag;
} else {
return NULL;
}
}
/*---------------------------------------------------------------------------*/
rpl_parent_t *
rpl_find_parent_any_dag(rpl_instance_t *instance, uip_ipaddr_t *addr)
{
rpl_parent_t *p;
rpl_dag_t *dag, *end;
for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DAG_PER_INSTANCE; dag < end; ++dag) {
if(dag->used) {
for(p = list_head(dag->parents); p != NULL; p = p->next) {
if(uip_ipaddr_cmp(&p->addr, addr)) {
rpl_parent_t *p = find_parent_any_dag_any_instance(addr);
if(p && p->dag && p->dag->instance == instance) {
return p;
}
}
}
}
} else {
return NULL;
}
}
/*---------------------------------------------------------------------------*/
rpl_dag_t *
@ -636,7 +633,7 @@ rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p)
best_dag->min_rank = best_dag->rank;
} else if(!acceptable_rank(best_dag, best_dag->rank)) {
PRINTF("RPL: New rank unacceptable!\n");
instance->current_dag->preferred_parent = NULL;
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);
@ -645,7 +642,7 @@ rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p)
}
if(best_dag->preferred_parent != last_parent) {
rpl_set_default_route(instance, &best_dag->preferred_parent->addr);
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++);
@ -672,7 +669,9 @@ rpl_select_parent(rpl_dag_t *dag)
rpl_parent_t *p, *best;
best = NULL;
for(p = list_head(dag->parents); p != NULL; p = p->next) {
p = nbr_table_head(rpl_parents);
while(p != NULL) {
if(p->rank == INFINITE_RANK) {
/* ignore this neighbor */
} else if(best == NULL) {
@ -680,40 +679,41 @@ rpl_select_parent(rpl_dag_t *dag)
} else {
best = dag->instance->of->best_parent(best, p);
}
p = nbr_table_next(rpl_parents, p);
}
if(best != NULL) {
dag->preferred_parent = best;
rpl_set_preferred_parent(dag, best);
}
return best;
}
/*---------------------------------------------------------------------------*/
void
rpl_remove_parent(rpl_dag_t *dag, rpl_parent_t *parent)
rpl_remove_parent(rpl_parent_t *parent)
{
rpl_nullify_parent(dag, parent);
PRINTF("RPL: Removing parent ");
PRINT6ADDR(&parent->addr);
PRINT6ADDR(rpl_get_parent_ipaddr(parent));
PRINTF("\n");
list_remove(dag->parents, parent);
memb_free(&parent_memb, parent);
rpl_nullify_parent(parent);
nbr_table_remove(rpl_parents, parent);
}
/*---------------------------------------------------------------------------*/
void
rpl_nullify_parent(rpl_dag_t *dag, rpl_parent_t *parent)
rpl_nullify_parent(rpl_parent_t *parent)
{
rpl_dag_t *dag = parent->dag;
/* This function can be called when the preferred parent is NULL, so we
need to handle this condition in order to trigger uip_ds6_defrt_rm. */
if(parent == dag->preferred_parent || dag->preferred_parent == NULL) {
dag->preferred_parent = NULL;
rpl_set_preferred_parent(dag, NULL);
dag->rank = INFINITE_RANK;
if(dag->joined) {
if(dag->instance->def_route != NULL) {
PRINTF("RPL: Removing default route ");
PRINT6ADDR(&parent->addr);
PRINT6ADDR(rpl_get_parent_ipaddr(parent));
PRINTF("\n");
uip_ds6_defrt_rm(dag->instance->def_route);
dag->instance->def_route = NULL;
@ -723,7 +723,7 @@ rpl_nullify_parent(rpl_dag_t *dag, rpl_parent_t *parent)
}
PRINTF("RPL: Nullifying parent ");
PRINT6ADDR(&parent->addr);
PRINT6ADDR(rpl_get_parent_ipaddr(parent));
PRINTF("\n");
}
/*---------------------------------------------------------------------------*/
@ -731,11 +731,11 @@ void
rpl_move_parent(rpl_dag_t *dag_src, rpl_dag_t *dag_dst, rpl_parent_t *parent)
{
if(parent == dag_src->preferred_parent) {
dag_src->preferred_parent = NULL;
rpl_set_preferred_parent(dag_src, NULL);
dag_src->rank = INFINITE_RANK;
if(dag_src->joined && dag_src->instance->def_route != NULL) {
PRINTF("RPL: Removing default route ");
PRINT6ADDR(&parent->addr);
PRINT6ADDR(rpl_get_parent_ipaddr(parent));
PRINTF("\n");
PRINTF("rpl_move_parent\n");
uip_ds6_defrt_rm(dag_src->instance->def_route);
@ -743,11 +743,11 @@ rpl_move_parent(rpl_dag_t *dag_src, rpl_dag_t *dag_dst, rpl_parent_t *parent)
}
} else if(dag_src->joined) {
/* Remove uIPv6 routes that have this parent as the next hop. */
rpl_remove_routes_by_nexthop(&parent->addr, dag_src);
rpl_remove_routes_by_nexthop(rpl_get_parent_ipaddr(parent), dag_src);
}
PRINTF("RPL: Moving parent ");
PRINT6ADDR(&parent->addr);
PRINT6ADDR(rpl_get_parent_ipaddr(parent));
PRINTF("\n");
list_remove(dag_src->parents, parent);
@ -831,7 +831,7 @@ rpl_join_instance(uip_ipaddr_t *from, rpl_dio_t *dio)
if(of == NULL) {
PRINTF("RPL: DIO for DAG instance %u does not specify a supported OF\n",
dio->instance_id);
rpl_remove_parent(dag, p);
rpl_remove_parent(p);
instance->used = 0;
return;
}
@ -866,7 +866,7 @@ rpl_join_instance(uip_ipaddr_t *from, rpl_dio_t *dio)
/* Copy prefix information from the DIO into the DAG object. */
memcpy(&dag->prefix_info, &dio->prefix_info, sizeof(rpl_prefix_t));
dag->preferred_parent = p;
rpl_set_preferred_parent(dag, p);
instance->of->update_metric_container(instance);
dag->rank = instance->of->calculate_rank(p, 0);
/* So far this is the lowest rank we are aware of. */
@ -943,7 +943,7 @@ rpl_add_dag(uip_ipaddr_t *from, rpl_dio_t *dio)
instance->lifetime_unit != dio->lifetime_unit) {
PRINTF("RPL: DIO for DAG instance %u uncompatible with previos DIO\n",
dio->instance_id);
rpl_remove_parent(dag, p);
rpl_remove_parent(p);
dag->used = 0;
return;
}
@ -958,7 +958,7 @@ rpl_add_dag(uip_ipaddr_t *from, rpl_dio_t *dio)
/* copy prefix information into the dag */
memcpy(&dag->prefix_info, &dio->prefix_info, sizeof(rpl_prefix_t));
dag->preferred_parent = p;
rpl_set_preferred_parent(dag, p);
dag->rank = instance->of->calculate_rank(p, 0);
dag->min_rank = dag->rank; /* So far this is the lowest rank we know of. */
@ -1022,38 +1022,22 @@ rpl_local_repair(rpl_instance_t *instance)
void
rpl_recalculate_ranks(void)
{
rpl_instance_t *instance, *end;
rpl_parent_t *p;
int i;
/*
* 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.
*/
for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES;
instance < end; ++instance) {
if(instance->used) {
for(i = 0; i < RPL_MAX_DAG_PER_INSTANCE; i++) {
if(instance->dag_table[i].used) {
for(p = list_head(instance->dag_table[i].parents);
p != NULL; p = p->next) {
if(p->updated) {
p = nbr_table_head(rpl_parents);
while(p != NULL) {
if(p->dag != NULL && p->dag->instance && p->updated) {
p->updated = 0;
if(!rpl_process_parent_event(instance, p)) {
if(!rpl_process_parent_event(p->dag->instance, p)) {
PRINTF("RPL: A parent was dropped\n");
}
/*
* 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;
}
}
}
}
}
p = nbr_table_next(rpl_parents, p);
}
}
/*---------------------------------------------------------------------------*/
@ -1070,11 +1054,10 @@ rpl_process_parent_event(rpl_instance_t *instance, rpl_parent_t *p)
/* 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) {
rpl_nullify_parent(p->dag, p);
return 0;
} else {
rpl_nullify_parent(p->dag, p);
return_value = 0;
}
}
@ -1092,7 +1075,7 @@ rpl_process_parent_event(rpl_instance_t *instance, rpl_parent_t *p)
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(&instance->current_dag->preferred_parent->addr);
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 {
@ -1196,10 +1179,6 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
if(p == NULL) {
previous_dag = find_parent_dag(instance, from);
if(previous_dag == NULL) {
if(RPL_PARENT_COUNT(dag) == RPL_MAX_PARENTS_PER_DAG) {
/* Make room for a new parent. */
remove_worst_parent(dag, dio->rank);
}
/* Add the DIO sender as a candidate parent. */
p = rpl_add_parent(dag, dio, from);
if(p == NULL) {

View file

@ -664,7 +664,7 @@ dao_input(void)
if(lifetime == RPL_ZERO_LIFETIME) {
/* No-Path DAO received; invoke the route purging routine. */
if(rep != NULL && rep->state.nopath_received == 0 && rep->length == prefixlen && uip_ipaddr_cmp(&rep->nexthop, &dao_sender_addr)) {
if(rep != NULL && rep->state.nopath_received == 0 && rep->length == prefixlen && uip_ipaddr_cmp(uip_ds6_route_nexthop(rep), &dao_sender_addr)) {
PRINTF("RPL: Setting expiration timer for prefix ");
PRINT6ADDR(&prefix);
PRINTF("\n");
@ -706,7 +706,7 @@ dao_input(void)
PRINTF("RPL: Forwarding DAO to parent ");
PRINT6ADDR(&dag->preferred_parent->addr);
PRINTF("\n");
uip_icmp6_send(&dag->preferred_parent->addr,
uip_icmp6_send(rpl_get_parent_ipaddr(dag->preferred_parent),
ICMP6_RPL, RPL_CODE_DAO, buffer_length);
}
if(flags & RPL_DAO_K_FLAG) {
@ -792,7 +792,7 @@ dao_output_target(rpl_parent_t *parent, uip_ipaddr_t *prefix, uint8_t lifetime)
PRINT6ADDR(&parent->addr);
PRINTF("\n");
uip_icmp6_send(&parent->addr, ICMP6_RPL, RPL_CODE_DAO, pos);
uip_icmp6_send(rpl_get_parent_ipaddr(parent), ICMP6_RPL, RPL_CODE_DAO, pos);
}
/*---------------------------------------------------------------------------*/
static void

View file

@ -290,8 +290,8 @@ void rpl_free_instance(rpl_instance_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 *);
rpl_parent_t *rpl_find_parent_any_dag(rpl_instance_t *instance, uip_ipaddr_t *addr);
void rpl_nullify_parent(rpl_dag_t *, rpl_parent_t *);
void rpl_remove_parent(rpl_dag_t *, rpl_parent_t *);
void rpl_nullify_parent(rpl_parent_t *);
void rpl_remove_parent(rpl_parent_t *);
void rpl_move_parent(rpl_dag_t *dag_src, rpl_dag_t *dag_dst, rpl_parent_t *parent);
rpl_parent_t *rpl_select_parent(rpl_dag_t *dag);
rpl_dag_t *rpl_select_dag(rpl_instance_t *instance,rpl_parent_t *parent);

View file

@ -240,6 +240,7 @@ rpl_init(void)
PRINTF("RPL started\n");
default_instance = NULL;
rpl_dag_init();
rpl_reset_periodic_timer();
neighbor_info_subscribe(rpl_link_neighbor_callback);

View file

@ -113,9 +113,8 @@ struct rpl_parent {
#if RPL_DAG_MC != RPL_DAG_MC_NONE
rpl_metric_container_t mc;
#endif /* RPL_DAG_MC != RPL_DAG_MC_NONE */
uip_ipaddr_t addr;
rpl_rank_t rank;
uint8_t link_metric;
uint16_t link_metric;
uint8_t dtsn;
uint8_t updated;
};
@ -243,5 +242,8 @@ int rpl_update_header_final(uip_ipaddr_t *addr);
int rpl_verify_header(int);
void rpl_remove_header(void);
uint8_t rpl_invert_header(void);
uip_ipaddr_t *rpl_get_parent_ipaddr(rpl_parent_t *nbr);
rpl_rank_t rpl_get_parent_rank(uip_lladdr_t *addr);
void rpl_dag_init();
/*---------------------------------------------------------------------------*/
#endif /* RPL_H */