Merge pull request #454 from adamdunkels/push/dao-updates-rebased

RPL feather mode
This commit is contained in:
Nicolas Tsiftes 2013-11-24 07:49:49 -08:00
commit 7283e48f09
9 changed files with 229 additions and 24 deletions

View file

@ -78,10 +78,16 @@ NBR_TABLE(rpl_parent_t, rpl_parents);
rpl_instance_t instance_table[RPL_MAX_INSTANCES]; rpl_instance_t instance_table[RPL_MAX_INSTANCES];
rpl_instance_t *default_instance; rpl_instance_t *default_instance;
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void
nbr_callback(void *ptr)
{
rpl_remove_parent(ptr);
}
void void
rpl_dag_init(void) rpl_dag_init(void)
{ {
nbr_table_register(rpl_parents, (nbr_table_callback *)rpl_remove_parent); nbr_table_register(rpl_parents, (nbr_table_callback *)nbr_callback);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
rpl_rank_t rpl_rank_t
@ -178,7 +184,7 @@ nullify_parents(rpl_dag_t *dag, rpl_rank_t minimum_rank)
{ {
rpl_parent_t *p; rpl_parent_t *p;
PRINTF("RPL: Removing parents (minimum rank %u)\n", PRINTF("RPL: Nullifying parents (minimum rank %u)\n",
minimum_rank); minimum_rank);
p = nbr_table_head(rpl_parents); p = nbr_table_head(rpl_parents);
@ -541,17 +547,23 @@ rpl_add_parent(rpl_dag_t *dag, rpl_dio_t *dio, uip_ipaddr_t *addr)
* Typically, the parent is added upon receiving a DIO. */ * Typically, the parent is added upon receiving a DIO. */
const uip_lladdr_t *lladdr = uip_ds6_nbr_lladdr_from_ipaddr(addr); const uip_lladdr_t *lladdr = uip_ds6_nbr_lladdr_from_ipaddr(addr);
PRINTF("RPL: rpl_add_parent lladdr %p\n", lladdr); PRINTF("RPL: rpl_add_parent lladdr %p ", lladdr);
PRINT6ADDR(addr);
PRINTF("\n");
if(lladdr != NULL) { if(lladdr != NULL) {
/* Add parent in rpl_parents */ /* Add parent in rpl_parents */
p = nbr_table_add_lladdr(rpl_parents, (rimeaddr_t *)lladdr); p = nbr_table_add_lladdr(rpl_parents, (rimeaddr_t *)lladdr);
p->dag = dag; if(p == NULL) {
p->rank = dio->rank; PRINTF("RPL: rpl_add_parent p NULL\n");
p->dtsn = dio->dtsn; } else {
p->link_metric = RPL_INIT_LINK_METRIC * RPL_DAG_MC_ETX_DIVISOR; p->dag = dag;
p->rank = dio->rank;
p->dtsn = dio->dtsn;
p->link_metric = RPL_INIT_LINK_METRIC * RPL_DAG_MC_ETX_DIVISOR;
#if RPL_DAG_MC != RPL_DAG_MC_NONE #if RPL_DAG_MC != RPL_DAG_MC_NONE
memcpy(&p->mc, &dio->mc, sizeof(p->mc)); memcpy(&p->mc, &dio->mc, sizeof(p->mc));
#endif /* RPL_DAG_MC != RPL_DAG_MC_NONE */ #endif /* RPL_DAG_MC != RPL_DAG_MC_NONE */
}
} }
return p; return p;
@ -689,8 +701,8 @@ rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p)
return best_dag; return best_dag;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
rpl_parent_t * static rpl_parent_t *
rpl_select_parent(rpl_dag_t *dag) best_parent(rpl_dag_t *dag)
{ {
rpl_parent_t *p, *best; rpl_parent_t *p, *best;
@ -708,6 +720,14 @@ rpl_select_parent(rpl_dag_t *dag)
p = nbr_table_next(rpl_parents, p); p = nbr_table_next(rpl_parents, p);
} }
return best;
}
/*---------------------------------------------------------------------------*/
rpl_parent_t *
rpl_select_parent(rpl_dag_t *dag)
{
rpl_parent_t *best = best_parent(dag);
if(best != NULL) { if(best != NULL) {
rpl_set_preferred_parent(dag, best); rpl_set_preferred_parent(dag, best);
} }
@ -776,9 +796,7 @@ rpl_move_parent(rpl_dag_t *dag_src, rpl_dag_t *dag_dst, rpl_parent_t *parent)
PRINT6ADDR(rpl_get_parent_ipaddr(parent)); PRINT6ADDR(rpl_get_parent_ipaddr(parent));
PRINTF("\n"); PRINTF("\n");
list_remove(dag_src->parents, parent);
parent->dag = dag_dst; parent->dag = dag_dst;
list_add(dag_dst->parents, parent);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
rpl_dag_t * rpl_dag_t *
@ -1192,7 +1210,7 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
} else if(dio->rank == INFINITE_RANK && dag->joined) { } else if(dio->rank == INFINITE_RANK && dag->joined) {
rpl_reset_dio_timer(instance); rpl_reset_dio_timer(instance);
} }
/* Prefix Information Option treated to add new prefix */ /* Prefix Information Option treated to add new prefix */
if(dio->prefix_info.length != 0) { if(dio->prefix_info.length != 0) {
if(dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) { if(dio->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS) {
@ -1277,4 +1295,10 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
p->dtsn = dio->dtsn; p->dtsn = dio->dtsn;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void
rpl_lock_parent(rpl_parent_t *p)
{
nbr_table_lock(rpl_parents, p);
}
/*---------------------------------------------------------------------------*/
#endif /* UIP_CONF_IPV6 */ #endif /* UIP_CONF_IPV6 */

View file

@ -69,6 +69,7 @@ rpl_verify_header(int uip_ext_opt_offset)
rpl_instance_t *instance; rpl_instance_t *instance;
int down; int down;
uint8_t sender_closer; uint8_t sender_closer;
uip_ds6_route_t *route;
if(UIP_EXT_HDR_OPT_RPL_BUF->opt_len != RPL_HDR_OPT_LEN) { if(UIP_EXT_HDR_OPT_RPL_BUF->opt_len != RPL_HDR_OPT_LEN) {
PRINTF("RPL: Bad header option! (wrong length)\n"); PRINTF("RPL: Bad header option! (wrong length)\n");
@ -83,11 +84,11 @@ rpl_verify_header(int uip_ext_opt_offset)
} }
if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_FWD_ERR) { if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_FWD_ERR) {
PRINTF("RPL: Forward error!\n");
/* We should try to repair it by removing the neighbor that caused /* We should try to repair it by removing the neighbor that caused
the packet to be forwareded in the first place. We drop any the packet to be forwareded in the first place. We drop any
routes that go through the neighbor that sent the packet to routes that go through the neighbor that sent the packet to
us. */ us. */
uip_ds6_route_t *route;
route = uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr); route = uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr);
if(route != NULL) { if(route != NULL) {
uip_ds6_route_rm(route); uip_ds6_route_rm(route);

View file

@ -146,7 +146,8 @@ dis_input(void)
PRINT6ADDR(&UIP_IP_BUF->srcipaddr); PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
PRINTF("\n"); PRINTF("\n");
for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES; instance < end; ++instance) { for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES;
instance < end; ++instance) {
if(instance->used == 1) { if(instance->used == 1) {
#if RPL_LEAF_ONLY #if RPL_LEAF_ONLY
if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) { if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
@ -578,6 +579,7 @@ dao_input(void)
int i; int i;
int learned_from; int learned_from;
rpl_parent_t *p; rpl_parent_t *p;
uip_ds6_nbr_t *nbr;
prefixlen = 0; prefixlen = 0;
@ -667,6 +669,20 @@ dao_input(void)
PRINTF("\n"); PRINTF("\n");
rep->state.nopath_received = 1; rep->state.nopath_received = 1;
rep->state.lifetime = DAO_EXPIRATION_TIMEOUT; rep->state.lifetime = DAO_EXPIRATION_TIMEOUT;
/* We forward the incoming no-path DAO to our parent, if we have
one. */
if(dag->preferred_parent != NULL &&
rpl_get_parent_ipaddr(dag->preferred_parent) != NULL) {
PRINTF("RPL: Forwarding no-path DAO to parent ");
PRINT6ADDR(rpl_get_parent_ipaddr(dag->preferred_parent));
PRINTF("\n");
uip_icmp6_send(rpl_get_parent_ipaddr(dag->preferred_parent),
ICMP6_RPL, RPL_CODE_DAO, buffer_length);
}
if(flags & RPL_DAO_K_FLAG) {
dao_ack_output(instance, &dao_sender_addr, sequence);
}
} }
return; return;
} }
@ -700,6 +716,32 @@ dao_input(void)
} }
PRINTF("RPL: adding DAO route\n"); PRINTF("RPL: adding DAO route\n");
if((nbr = uip_ds6_nbr_lookup(&dao_sender_addr)) == NULL) {
if((nbr = uip_ds6_nbr_add(&dao_sender_addr,
(uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER),
0, NBR_REACHABLE)) != NULL) {
/* set reachable timer */
stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
PRINTF("RPL: Neighbor added to neighbor cache ");
PRINT6ADDR(&dao_sender_addr);
PRINTF(", ");
PRINTLLADDR((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
PRINTF("\n");
} else {
PRINTF("RPL: Out of Memory, dropping DAO from ");
PRINT6ADDR(&dao_sender_addr);
PRINTF(", ");
PRINTLLADDR((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
PRINTF("\n");
return;
}
} else {
PRINTF("RPL: Neighbor already in neighbor cache\n");
}
rpl_lock_parent(p);
rep = rpl_add_route(dag, &prefix, prefixlen, &dao_sender_addr); rep = rpl_add_route(dag, &prefix, prefixlen, &dao_sender_addr);
if(rep == NULL) { if(rep == NULL) {
RPL_STAT(rpl_stats.mem_overflows++); RPL_STAT(rpl_stats.mem_overflows++);
@ -751,6 +793,11 @@ dao_output_target(rpl_parent_t *parent, uip_ipaddr_t *prefix, uint8_t lifetime)
/* Destination Advertisement Object */ /* Destination Advertisement Object */
/* If we are in feather mode, we should not send any DAOs */
if(rpl_get_mode() == RPL_MODE_FEATHER) {
return;
}
if(parent == NULL) { if(parent == NULL) {
PRINTF("RPL dao_output_target error parent NULL\n"); PRINTF("RPL dao_output_target error parent NULL\n");
return; return;

View file

@ -304,11 +304,17 @@ uip_ds6_route_t *rpl_add_route(rpl_dag_t *dag, uip_ipaddr_t *prefix,
int prefix_len, uip_ipaddr_t *next_hop); int prefix_len, uip_ipaddr_t *next_hop);
void rpl_purge_routes(void); void rpl_purge_routes(void);
/* Lock a parent in the neighbor cache. */
void rpl_lock_parent(rpl_parent_t *p);
/* Objective function. */ /* Objective function. */
rpl_of_t *rpl_find_of(rpl_ocp_t); rpl_of_t *rpl_find_of(rpl_ocp_t);
/* Timer functions. */ /* Timer functions. */
void rpl_schedule_dao(rpl_instance_t *); void rpl_schedule_dao(rpl_instance_t *);
void rpl_schedule_dao_immediately(rpl_instance_t *);
void rpl_cancel_dao(rpl_instance_t *instance);
void rpl_reset_dio_timer(rpl_instance_t *); void rpl_reset_dio_timer(rpl_instance_t *);
void rpl_reset_periodic_timer(void); void rpl_reset_periodic_timer(void);

View file

@ -194,6 +194,28 @@ rpl_reset_dio_timer(rpl_instance_t *instance)
#endif /* RPL_LEAF_ONLY */ #endif /* RPL_LEAF_ONLY */
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void handle_dao_timer(void *ptr);
static void
set_dao_lifetime_timer(rpl_instance_t *instance)
{
if(rpl_get_mode() == RPL_MODE_FEATHER) {
return;
}
/* Set up another DAO within half the expiration time, if such a
time has been configured */
if(instance->lifetime_unit != 0xffff && instance->default_lifetime != 0xff) {
clock_time_t expiration_time;
expiration_time = (clock_time_t)instance->default_lifetime *
(clock_time_t)instance->lifetime_unit *
CLOCK_SECOND / 2;
PRINTF("RPL: Scheduling DAO lifetime timer %u ticks in the future\n",
(unsigned)expiration_time);
ctimer_set(&instance->dao_lifetime_timer, expiration_time,
handle_dao_timer, instance);
}
}
/*---------------------------------------------------------------------------*/
static void static void
handle_dao_timer(void *ptr) handle_dao_timer(void *ptr)
{ {
@ -215,26 +237,60 @@ handle_dao_timer(void *ptr)
} else { } else {
PRINTF("RPL: No suitable DAO parent\n"); PRINTF("RPL: No suitable DAO parent\n");
} }
ctimer_stop(&instance->dao_timer); ctimer_stop(&instance->dao_timer);
if(etimer_expired(&instance->dao_lifetime_timer.etimer)) {
set_dao_lifetime_timer(instance);
}
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void static void
rpl_schedule_dao(rpl_instance_t *instance) schedule_dao(rpl_instance_t *instance, clock_time_t latency)
{ {
clock_time_t expiration_time; clock_time_t expiration_time;
if(rpl_get_mode() == RPL_MODE_FEATHER) {
return;
}
expiration_time = etimer_expiration_time(&instance->dao_timer.etimer); expiration_time = etimer_expiration_time(&instance->dao_timer.etimer);
if(!etimer_expired(&instance->dao_timer.etimer)) { if(!etimer_expired(&instance->dao_timer.etimer)) {
PRINTF("RPL: DAO timer already scheduled\n"); PRINTF("RPL: DAO timer already scheduled\n");
} else { } else {
expiration_time = RPL_DAO_LATENCY / 2 + if(latency != 0) {
(random_rand() % (RPL_DAO_LATENCY)); expiration_time = latency / 2 +
(random_rand() % (latency));
} else {
expiration_time = 0;
}
PRINTF("RPL: Scheduling DAO timer %u ticks in the future\n", PRINTF("RPL: Scheduling DAO timer %u ticks in the future\n",
(unsigned)expiration_time); (unsigned)expiration_time);
ctimer_set(&instance->dao_timer, expiration_time, ctimer_set(&instance->dao_timer, expiration_time,
handle_dao_timer, instance); handle_dao_timer, instance);
set_dao_lifetime_timer(instance);
} }
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void
rpl_schedule_dao(rpl_instance_t *instance)
{
schedule_dao(instance, RPL_DAO_LATENCY);
}
/*---------------------------------------------------------------------------*/
void
rpl_schedule_dao_immediately(rpl_instance_t *instance)
{
schedule_dao(instance, 0);
}
/*---------------------------------------------------------------------------*/
void
rpl_cancel_dao(rpl_instance_t *instance)
{
ctimer_stop(&instance->dao_timer);
ctimer_stop(&instance->dao_lifetime_timer);
}
/*---------------------------------------------------------------------------*/
#endif /* UIP_CONF_IPV6 */ #endif /* UIP_CONF_IPV6 */

View file

@ -57,6 +57,47 @@
rpl_stats_t rpl_stats; rpl_stats_t rpl_stats;
#endif #endif
static enum rpl_mode mode = RPL_MODE_MESH;
/*---------------------------------------------------------------------------*/
enum rpl_mode
rpl_get_mode(void)
{
return mode;
}
/*---------------------------------------------------------------------------*/
enum rpl_mode
rpl_set_mode(enum rpl_mode m)
{
enum rpl_mode oldmode = mode;
/* We need to do different things depending on what mode we are
switching to. */
if(m == RPL_MODE_MESH) {
/* If we switcht to mesh mode, we should send out a DAO message to
inform our parent that we now are reachable. Before we do this,
we must set the mode variable, since DAOs will not be send if
we are in feather mode. */
PRINTF("RPL: switching to mesh mode\n");
mode = m;
if(default_instance != NULL) {
rpl_schedule_dao_immediately(default_instance);
}
} else if(m == RPL_MODE_FEATHER) {
PRINTF("RPL: switching to feather mode\n");
mode = m;
if(default_instance != NULL) {
rpl_cancel_dao(default_instance);
}
} else {
mode = m;
}
return oldmode;
}
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void void
rpl_purge_routes(void) rpl_purge_routes(void)

View file

@ -45,9 +45,6 @@
#include "net/uip-ds6.h" #include "net/uip-ds6.h"
#include "sys/ctimer.h" #include "sys/ctimer.h"
/*---------------------------------------------------------------------------*/
/* The amount of parents that this node has in a particular DAG. */
#define RPL_PARENT_COUNT(dag) list_length((dag)->parents)
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
typedef uint16_t rpl_rank_t; typedef uint16_t rpl_rank_t;
typedef uint16_t rpl_ocp_t; typedef uint16_t rpl_ocp_t;
@ -142,7 +139,6 @@ struct rpl_dag {
rpl_parent_t *preferred_parent; rpl_parent_t *preferred_parent;
rpl_rank_t rank; rpl_rank_t rank;
struct rpl_instance *instance; struct rpl_instance *instance;
LIST_STRUCT(parents);
rpl_prefix_t prefix_info; rpl_prefix_t prefix_info;
}; };
typedef struct rpl_dag rpl_dag_t; typedef struct rpl_dag rpl_dag_t;
@ -225,6 +221,7 @@ struct rpl_instance {
clock_time_t dio_next_delay; /* delay for completion of dio interval */ clock_time_t dio_next_delay; /* delay for completion of dio interval */
struct ctimer dio_timer; struct ctimer dio_timer;
struct ctimer dao_timer; struct ctimer dao_timer;
struct ctimer dao_lifetime_timer;
}; };
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
@ -247,5 +244,38 @@ uip_ipaddr_t *rpl_get_parent_ipaddr(rpl_parent_t *nbr);
rpl_rank_t rpl_get_parent_rank(uip_lladdr_t *addr); rpl_rank_t rpl_get_parent_rank(uip_lladdr_t *addr);
uint16_t rpl_get_parent_link_metric(const uip_lladdr_t *addr); uint16_t rpl_get_parent_link_metric(const uip_lladdr_t *addr);
void rpl_dag_init(void); void rpl_dag_init(void);
/**
* RPL modes
*
* The RPL module can be in either of three modes: mesh mode
* (RPL_MODE_MESH), feater mode (RPL_MODE_FEATHER), and leaf mode
* (RPL_MODE_LEAF). In mesh mode, nodes forward data for other nodes,
* and are reachable by others. In feather mode, nodes can forward
* data for other nodes, but are not reachable themselves. In leaf
* mode, nodes do not forward data for others, but are reachable by
* others. */
enum rpl_mode {
RPL_MODE_MESH = 0,
RPL_MODE_FEATHER = 1,
RPL_MODE_LEAF = 2,
};
/**
* Set the RPL mode
*
* \param mode The new RPL mode
* \retval The previous RPL mode
*/
enum rpl_mode rpl_set_mode(enum rpl_mode mode);
/**
* Get the RPL mode
*
* \retval The RPL mode
*/
enum rpl_mode rpl_get_mode(void);
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
#endif /* RPL_H */ #endif /* RPL_H */

View file

@ -142,7 +142,7 @@ collect_common_send(void)
} }
rtmetric = dag->rank; rtmetric = dag->rank;
beacon_interval = (uint16_t) ((2L << dag->instance->dio_intcurrent) / 1000); beacon_interval = (uint16_t) ((2L << dag->instance->dio_intcurrent) / 1000);
num_neighbors = RPL_PARENT_COUNT(dag); num_neighbors = uip_ds6_nbr_num();
} else { } else {
rtmetric = 0; rtmetric = 0;
beacon_interval = 0; beacon_interval = 0;