Merge pull request #454 from adamdunkels/push/dao-updates-rebased
RPL feather mode
This commit is contained in:
commit
7283e48f09
|
@ -78,10 +78,16 @@ NBR_TABLE(rpl_parent_t, rpl_parents);
|
|||
rpl_instance_t instance_table[RPL_MAX_INSTANCES];
|
||||
rpl_instance_t *default_instance;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
nbr_callback(void *ptr)
|
||||
{
|
||||
rpl_remove_parent(ptr);
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -178,7 +184,7 @@ nullify_parents(rpl_dag_t *dag, rpl_rank_t minimum_rank)
|
|||
{
|
||||
rpl_parent_t *p;
|
||||
|
||||
PRINTF("RPL: Removing parents (minimum rank %u)\n",
|
||||
PRINTF("RPL: Nullifying parents (minimum rank %u)\n",
|
||||
minimum_rank);
|
||||
|
||||
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. */
|
||||
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) {
|
||||
/* 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;
|
||||
p->link_metric = RPL_INIT_LINK_METRIC * RPL_DAG_MC_ETX_DIVISOR;
|
||||
if(p == NULL) {
|
||||
PRINTF("RPL: rpl_add_parent p NULL\n");
|
||||
} else {
|
||||
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
|
||||
memcpy(&p->mc, &dio->mc, sizeof(p->mc));
|
||||
memcpy(&p->mc, &dio->mc, sizeof(p->mc));
|
||||
#endif /* RPL_DAG_MC != RPL_DAG_MC_NONE */
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
|
@ -689,8 +701,8 @@ rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p)
|
|||
return best_dag;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
rpl_parent_t *
|
||||
rpl_select_parent(rpl_dag_t *dag)
|
||||
static rpl_parent_t *
|
||||
best_parent(rpl_dag_t *dag)
|
||||
{
|
||||
rpl_parent_t *p, *best;
|
||||
|
||||
|
@ -708,6 +720,14 @@ rpl_select_parent(rpl_dag_t *dag)
|
|||
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) {
|
||||
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));
|
||||
PRINTF("\n");
|
||||
|
||||
list_remove(dag_src->parents, parent);
|
||||
parent->dag = dag_dst;
|
||||
list_add(dag_dst->parents, parent);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
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) {
|
||||
rpl_reset_dio_timer(instance);
|
||||
}
|
||||
|
||||
|
||||
/* Prefix Information Option treated to add new prefix */
|
||||
if(dio->prefix_info.length != 0) {
|
||||
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;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
rpl_lock_parent(rpl_parent_t *p)
|
||||
{
|
||||
nbr_table_lock(rpl_parents, p);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#endif /* UIP_CONF_IPV6 */
|
||||
|
|
|
@ -69,6 +69,7 @@ rpl_verify_header(int uip_ext_opt_offset)
|
|||
rpl_instance_t *instance;
|
||||
int down;
|
||||
uint8_t sender_closer;
|
||||
uip_ds6_route_t *route;
|
||||
|
||||
if(UIP_EXT_HDR_OPT_RPL_BUF->opt_len != RPL_HDR_OPT_LEN) {
|
||||
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) {
|
||||
PRINTF("RPL: Forward error!\n");
|
||||
/* We should try to repair it by removing the neighbor that caused
|
||||
the packet to be forwareded in the first place. We drop any
|
||||
routes that go through the neighbor that sent the packet to
|
||||
us. */
|
||||
uip_ds6_route_t *route;
|
||||
route = uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr);
|
||||
if(route != NULL) {
|
||||
uip_ds6_route_rm(route);
|
||||
|
|
|
@ -146,7 +146,8 @@ dis_input(void)
|
|||
PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
|
||||
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 RPL_LEAF_ONLY
|
||||
if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
|
||||
|
@ -578,6 +579,7 @@ dao_input(void)
|
|||
int i;
|
||||
int learned_from;
|
||||
rpl_parent_t *p;
|
||||
uip_ds6_nbr_t *nbr;
|
||||
|
||||
prefixlen = 0;
|
||||
|
||||
|
@ -667,6 +669,20 @@ dao_input(void)
|
|||
PRINTF("\n");
|
||||
rep->state.nopath_received = 1;
|
||||
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;
|
||||
}
|
||||
|
@ -700,6 +716,32 @@ dao_input(void)
|
|||
}
|
||||
|
||||
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);
|
||||
if(rep == NULL) {
|
||||
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 */
|
||||
|
||||
/* If we are in feather mode, we should not send any DAOs */
|
||||
if(rpl_get_mode() == RPL_MODE_FEATHER) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(parent == NULL) {
|
||||
PRINTF("RPL dao_output_target error parent NULL\n");
|
||||
return;
|
||||
|
|
|
@ -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);
|
||||
void rpl_purge_routes(void);
|
||||
|
||||
/* Lock a parent in the neighbor cache. */
|
||||
void rpl_lock_parent(rpl_parent_t *p);
|
||||
|
||||
/* Objective function. */
|
||||
rpl_of_t *rpl_find_of(rpl_ocp_t);
|
||||
|
||||
/* Timer functions. */
|
||||
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_periodic_timer(void);
|
||||
|
||||
|
|
|
@ -194,6 +194,28 @@ rpl_reset_dio_timer(rpl_instance_t *instance)
|
|||
#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
|
||||
handle_dao_timer(void *ptr)
|
||||
{
|
||||
|
@ -215,26 +237,60 @@ handle_dao_timer(void *ptr)
|
|||
} else {
|
||||
PRINTF("RPL: No suitable DAO parent\n");
|
||||
}
|
||||
|
||||
ctimer_stop(&instance->dao_timer);
|
||||
|
||||
if(etimer_expired(&instance->dao_lifetime_timer.etimer)) {
|
||||
set_dao_lifetime_timer(instance);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
rpl_schedule_dao(rpl_instance_t *instance)
|
||||
static void
|
||||
schedule_dao(rpl_instance_t *instance, clock_time_t latency)
|
||||
{
|
||||
clock_time_t expiration_time;
|
||||
|
||||
if(rpl_get_mode() == RPL_MODE_FEATHER) {
|
||||
return;
|
||||
}
|
||||
|
||||
expiration_time = etimer_expiration_time(&instance->dao_timer.etimer);
|
||||
|
||||
if(!etimer_expired(&instance->dao_timer.etimer)) {
|
||||
PRINTF("RPL: DAO timer already scheduled\n");
|
||||
} else {
|
||||
expiration_time = RPL_DAO_LATENCY / 2 +
|
||||
(random_rand() % (RPL_DAO_LATENCY));
|
||||
if(latency != 0) {
|
||||
expiration_time = latency / 2 +
|
||||
(random_rand() % (latency));
|
||||
} else {
|
||||
expiration_time = 0;
|
||||
}
|
||||
PRINTF("RPL: Scheduling DAO timer %u ticks in the future\n",
|
||||
(unsigned)expiration_time);
|
||||
ctimer_set(&instance->dao_timer, expiration_time,
|
||||
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 */
|
||||
|
|
|
@ -57,6 +57,47 @@
|
|||
rpl_stats_t rpl_stats;
|
||||
#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
|
||||
rpl_purge_routes(void)
|
||||
|
|
|
@ -45,9 +45,6 @@
|
|||
#include "net/uip-ds6.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_ocp_t;
|
||||
|
@ -142,7 +139,6 @@ struct rpl_dag {
|
|||
rpl_parent_t *preferred_parent;
|
||||
rpl_rank_t rank;
|
||||
struct rpl_instance *instance;
|
||||
LIST_STRUCT(parents);
|
||||
rpl_prefix_t prefix_info;
|
||||
};
|
||||
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 */
|
||||
struct ctimer dio_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);
|
||||
uint16_t rpl_get_parent_link_metric(const uip_lladdr_t *addr);
|
||||
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 */
|
||||
|
|
|
@ -142,7 +142,7 @@ collect_common_send(void)
|
|||
}
|
||||
rtmetric = dag->rank;
|
||||
beacon_interval = (uint16_t) ((2L << dag->instance->dio_intcurrent) / 1000);
|
||||
num_neighbors = RPL_PARENT_COUNT(dag);
|
||||
num_neighbors = uip_ds6_nbr_num();
|
||||
} else {
|
||||
rtmetric = 0;
|
||||
beacon_interval = 0;
|
||||
|
|
Loading…
Reference in a new issue