rpl-lite: added state to DAG and only start advertising once reachable, added poisoning and leaving after a delay, improved management of DAG expiration
This commit is contained in:
parent
0d357a5c84
commit
5df65382b3
@ -51,7 +51,7 @@ COOJA_BASE = simEnvChange.c cooja_mt.c cooja_mtarch.c rtimer-arch.c slip.c watch
|
||||
|
||||
COOJA_INTFS = beep.c button-sensor.c ip.c leds-arch.c moteid.c \
|
||||
pir-sensor.c rs232.c vib-sensor.c \
|
||||
clock.c log.c cfs-cooja.c cooja-radio.c \
|
||||
clock.c cooja-log.c cfs-cooja.c cooja-radio.c \
|
||||
eeprom.c slip-arch.c
|
||||
|
||||
COOJA_CORE = random.c sensors.c leds.c
|
||||
|
@ -248,31 +248,37 @@ tsch_reset(void)
|
||||
static void
|
||||
keepalive_packet_sent(void *ptr, int status, int transmissions)
|
||||
{
|
||||
if(tsch_is_associated) {
|
||||
#ifdef TSCH_LINK_NEIGHBOR_CALLBACK
|
||||
TSCH_LINK_NEIGHBOR_CALLBACK(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), status, transmissions);
|
||||
TSCH_LINK_NEIGHBOR_CALLBACK(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), status, transmissions);
|
||||
#endif
|
||||
LOG_INFO("KA sent to ");
|
||||
LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
|
||||
LOG_INFO_(", st %d-%d\n", status, transmissions);
|
||||
LOG_INFO("KA sent to ");
|
||||
LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
|
||||
LOG_INFO_(", st %d-%d\n", status, transmissions);
|
||||
|
||||
/* We got no ack, try to recover by switching to the last neighbor we received an EB from */
|
||||
if(status != MAC_TX_OK) {
|
||||
if(linkaddr_cmp(&last_eb_nbr_addr, &linkaddr_null)) {
|
||||
LOG_WARN("not able to re-synchronize, received no EB from other neighbors\n");
|
||||
} else {
|
||||
LOG_WARN("re-synchronizing on ");
|
||||
LOG_WARN_LLADDR(&last_eb_nbr_addr);
|
||||
LOG_WARN_("\n");
|
||||
/* We simply pick the last neighbor we receiver sync information from */
|
||||
tsch_queue_update_time_source(&last_eb_nbr_addr);
|
||||
tsch_join_priority = last_eb_nbr_jp + 1;
|
||||
/* Try to get in sync ASAP */
|
||||
tsch_schedule_keepalive_immediately();
|
||||
return;
|
||||
/* We got no ack, try to recover by switching to the last neighbor we received an EB from */
|
||||
if(status != MAC_TX_OK) {
|
||||
if(linkaddr_cmp(&last_eb_nbr_addr, &linkaddr_null)) {
|
||||
LOG_WARN("not able to re-synchronize, received no EB from other neighbors\n");
|
||||
if(sync_count == 0) {
|
||||
/* We got no synchronization at all in this session, leave the network */
|
||||
tsch_disassociate();
|
||||
}
|
||||
} else {
|
||||
LOG_WARN("re-synchronizing on ");
|
||||
LOG_WARN_LLADDR(&last_eb_nbr_addr);
|
||||
LOG_WARN_("\n");
|
||||
/* We simply pick the last neighbor we receiver sync information from */
|
||||
tsch_queue_update_time_source(&last_eb_nbr_addr);
|
||||
tsch_join_priority = last_eb_nbr_jp + 1;
|
||||
/* Try to get in sync ASAP */
|
||||
tsch_schedule_keepalive_immediately();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tsch_schedule_keepalive();
|
||||
tsch_schedule_keepalive();
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Prepare and send a keepalive message */
|
||||
@ -487,8 +493,6 @@ tsch_disassociate(void)
|
||||
if(tsch_is_associated == 1) {
|
||||
tsch_is_associated = 0;
|
||||
process_post(&tsch_process, PROCESS_EVENT_POLL, NULL);
|
||||
LOG_WARN("leaving the network, stats: tx %lu, rx %lu, sync %lu\n",
|
||||
tx_count, rx_count, sync_count);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
@ -769,6 +773,9 @@ PROCESS_THREAD(tsch_process, ev, data)
|
||||
* as long as we are associated */
|
||||
PROCESS_YIELD_UNTIL(!tsch_is_associated);
|
||||
|
||||
LOG_WARN("leaving the network, stats: tx %lu, rx %lu, sync %lu\n",
|
||||
tx_count, rx_count, sync_count);
|
||||
|
||||
/* Will need to re-synchronize */
|
||||
tsch_reset();
|
||||
}
|
||||
|
@ -166,9 +166,9 @@
|
||||
/*
|
||||
* Function used to send RPL probes.
|
||||
* To probe with DIO, use:
|
||||
* #define RPL_CONF_PROBING_SEND_FUNC(instance, addr) rpl_icmp6_dio_output((instance), (addr))
|
||||
* #define RPL_CONF_PROBING_SEND_FUNC(addr) rpl_icmp6_dio_output((addr))
|
||||
* To probe with DIS, use:
|
||||
* #define RPL_CONF_PROBING_SEND_FUNC(instance, addr) rpl_icmp6_dis_output((addr))
|
||||
* #define RPL_CONF_PROBING_SEND_FUNC(addr) rpl_icmp6_dis_output((addr))
|
||||
* Any other custom probing function is also acceptable.
|
||||
*/
|
||||
#ifdef RPL_CONF_PROBING_SEND_FUNC
|
||||
@ -257,6 +257,13 @@
|
||||
#define RPL_DEFAULT_LIFETIME RPL_CONF_DEFAULT_LIFETIME
|
||||
#endif
|
||||
|
||||
/* Maximum lifetime of a DAG as a multiple of the lifetime unit. */
|
||||
#ifdef RPL_CONF_DAG_LIFETIME
|
||||
#define RPL_DAG_LIFETIME RPL_CONF_DAG_LIFETIME
|
||||
#else
|
||||
#define RPL_DAG_LIFETIME (60 * 60) /* one hour */
|
||||
#endif /* RPL_CONF_DAG_LIFETIME */
|
||||
|
||||
/*
|
||||
* RPL probing interval.
|
||||
*/
|
||||
@ -275,10 +282,15 @@
|
||||
#define RPL_PROBING_DELAY_FUNC get_probing_delay
|
||||
#endif
|
||||
|
||||
|
||||
/* Poisoining duration, before leaving the DAG */
|
||||
#ifdef RPL_CONF_DELAY_BEFORE_LEAVING
|
||||
#define RPL_DELAY_BEFORE_LEAVING RPL_CONF_DELAY_BEFORE_LEAVING
|
||||
#else
|
||||
#define RPL_DELAY_BEFORE_LEAVING (5 * 60 * CLOCK_SECOND)
|
||||
#endif
|
||||
|
||||
/* Interval of DIS transmission */
|
||||
#ifdef RPL_CONF_DIS_INTERVAL
|
||||
#ifdef RPL_CONF_DIS_INTERVAL
|
||||
#define RPL_DIS_INTERVAL RPL_CONF_DIS_INTERVAL
|
||||
#else
|
||||
#define RPL_DIS_INTERVAL (30 * CLOCK_SECOND)
|
||||
|
@ -62,12 +62,29 @@ static int init_dag_from_dio(rpl_dio_t *dio);
|
||||
rpl_instance_t curr_instance;
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
leave_dag(const char *str)
|
||||
const char *
|
||||
rpl_dag_state_to_str(enum rpl_dag_state state)
|
||||
{
|
||||
switch(state) {
|
||||
case DAG_INITIALIZED:
|
||||
return "initialized";
|
||||
case DAG_JOINED:
|
||||
return "joined";
|
||||
case DAG_REACHABLE:
|
||||
return "reachable";
|
||||
case DAG_POISONING:
|
||||
return "poisoning";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
rpl_dag_leave(void)
|
||||
{
|
||||
LOG_INFO("leaving DAG ");
|
||||
LOG_INFO_6ADDR(&curr_instance.dag.dag_id);
|
||||
LOG_INFO_(", instance %u (%s)\n", curr_instance.instance_id, str);
|
||||
LOG_INFO_(", instance %u\n", curr_instance.instance_id);
|
||||
|
||||
/* Issue a no-path DAO */
|
||||
RPL_LOLLIPOP_INCREMENT(curr_instance.dag.dao_curr_seqno);
|
||||
@ -76,6 +93,7 @@ leave_dag(const char *str)
|
||||
/* Remove all neighbors */
|
||||
rpl_neighbor_remove_all();
|
||||
|
||||
/* Stop all timers */
|
||||
rpl_timers_stop_dag_timers();
|
||||
|
||||
/* Remove autoconfigured address */
|
||||
@ -95,7 +113,13 @@ rpl_dag_periodic(unsigned seconds)
|
||||
curr_instance.dag.lifetime =
|
||||
curr_instance.dag.lifetime > seconds ? curr_instance.dag.lifetime - seconds : 0;
|
||||
if(curr_instance.dag.lifetime == 0) {
|
||||
leave_dag("expired");
|
||||
LOG_WARN("DAG expired, poison and leave\n");
|
||||
curr_instance.dag.state = DAG_POISONING;
|
||||
rpl_timers_schedule_state_update();
|
||||
} else if(curr_instance.dag.lifetime < 300 && curr_instance.dag.preferred_parent != NULL) {
|
||||
/* Five minutes before expiring, start sending unicast DIS to get an update */
|
||||
LOG_WARN("DAG expiring in %u seconds, send DIS to preferred parent\n", (unsigned)curr_instance.dag.lifetime);
|
||||
rpl_icmp6_dis_output(rpl_neighbor_get_ipaddr(curr_instance.dag.preferred_parent));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -170,13 +194,23 @@ rpl_local_repair(const char *str)
|
||||
if(curr_instance.used) { /* Check needed because this is a public function */
|
||||
LOG_WARN("local repair (%s)\n", str);
|
||||
curr_instance.of->reset(); /* Reset OF */
|
||||
curr_instance.dag.is_reachable = 0; /* Assume we are no longer reachable */
|
||||
curr_instance.dag.state = DAG_INITIALIZED; /* Reset DAG state */
|
||||
rpl_neighbor_remove_all(); /* Remove all neighbors */
|
||||
rpl_timers_dio_reset("Local repair"); /* Reset Trickle timer */
|
||||
rpl_timers_schedule_state_update();
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
rpl_dag_ready_to_advertise(void)
|
||||
{
|
||||
if(curr_instance.mop == RPL_MOP_NO_DOWNWARD_ROUTES) {
|
||||
return curr_instance.used && curr_instance.dag.state >= DAG_INITIALIZED;
|
||||
} else {
|
||||
return curr_instance.used && curr_instance.dag.state >= DAG_REACHABLE;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Updates rank and parent */
|
||||
void
|
||||
rpl_dag_update_state(void)
|
||||
@ -184,37 +218,59 @@ rpl_dag_update_state(void)
|
||||
if(curr_instance.used) {
|
||||
if(!rpl_dag_root_is_root()) {
|
||||
rpl_nbr_t *old_parent = curr_instance.dag.preferred_parent;
|
||||
rpl_rank_t old_rank = curr_instance.dag.rank;
|
||||
|
||||
/* Any scheduled state update is no longer needed */
|
||||
rpl_timers_unschedule_state_update();
|
||||
|
||||
/* Select and set preferred parent */
|
||||
rpl_neighbor_set_preferred(rpl_neighbor_select_best());
|
||||
/* Update rank */
|
||||
curr_instance.dag.rank = rpl_neighbor_rank_via_nbr(curr_instance.dag.preferred_parent);
|
||||
|
||||
if(old_parent == NULL || curr_instance.dag.rank < curr_instance.dag.lowest_rank) {
|
||||
/* This is a slight departure from RFC6550: if we had no preferred parent before,
|
||||
* reset lowest_rank. This helps recovering from temporary bad link conditions. */
|
||||
curr_instance.dag.lowest_rank = curr_instance.dag.rank;
|
||||
}
|
||||
|
||||
/* Parent switch */
|
||||
if(curr_instance.dag.preferred_parent != old_parent) {
|
||||
/* Schedule a DAO */
|
||||
rpl_timers_schedule_dao();
|
||||
/* We just got a parent (was NULL), reset trickle timer to advertise this */
|
||||
if(old_parent == NULL) {
|
||||
rpl_timers_dio_reset("Got parent");
|
||||
if(curr_instance.dag.state == DAG_POISONING) {
|
||||
rpl_neighbor_set_preferred_parent(NULL);
|
||||
curr_instance.dag.rank = RPL_INFINITE_RANK;
|
||||
if(old_rank != RPL_INFINITE_RANK) {
|
||||
/* Advertise that we are leaving, and leave after a delay */
|
||||
LOG_WARN("poisoning and leaving after a delay\n");
|
||||
rpl_timers_dio_reset("Poison");
|
||||
rpl_timers_schedule_leaving();
|
||||
}
|
||||
/* We have no more parent, schedule DIS to get a chance to hear updated state */
|
||||
if(curr_instance.dag.preferred_parent == NULL) {
|
||||
LOG_WARN("no parnt, scheduling periodic DIS\n");
|
||||
rpl_timers_schedule_periodic_dis();
|
||||
} else {
|
||||
/* Select and set preferred parent */
|
||||
rpl_neighbor_set_preferred_parent(rpl_neighbor_select_best());
|
||||
/* Update rank */
|
||||
curr_instance.dag.rank = rpl_neighbor_rank_via_nbr(curr_instance.dag.preferred_parent);
|
||||
|
||||
if(old_parent == NULL || curr_instance.dag.rank < curr_instance.dag.lowest_rank) {
|
||||
/* This is a slight departure from RFC6550: if we had no preferred parent before,
|
||||
* reset lowest_rank. This helps recovering from temporary bad link conditions. */
|
||||
curr_instance.dag.lowest_rank = curr_instance.dag.rank;
|
||||
}
|
||||
|
||||
/* Parent switch */
|
||||
if(curr_instance.dag.preferred_parent != old_parent) {
|
||||
/* We just got a parent (was NULL), reset trickle timer to advertise this */
|
||||
if(old_parent == NULL) {
|
||||
curr_instance.dag.state = DAG_JOINED;
|
||||
rpl_timers_dio_reset("Got parent");
|
||||
LOG_WARN("found parent: ");
|
||||
LOG_WARN_6ADDR(rpl_neighbor_get_ipaddr(curr_instance.dag.preferred_parent));
|
||||
LOG_WARN_(", staying in DAG\n");
|
||||
rpl_timers_unschedule_leaving();
|
||||
}
|
||||
|
||||
/* Schedule a DAO */
|
||||
if(curr_instance.dag.preferred_parent != NULL) {
|
||||
rpl_timers_schedule_dao();
|
||||
} else {
|
||||
/* We have no more parent, schedule DIS to get a chance to hear updated state */
|
||||
curr_instance.dag.state = DAG_INITIALIZED;
|
||||
LOG_WARN("no parent, scheduling periodic DIS, will leave if no parent is found\n");
|
||||
rpl_timers_schedule_periodic_dis();
|
||||
rpl_timers_schedule_leaving();
|
||||
}
|
||||
|
||||
#if LOG_INFO_ENABLED
|
||||
rpl_neighbor_print_list("Parent switch");
|
||||
#endif /* LOG_INFO_ENABLED */
|
||||
}
|
||||
#if LOG_INFO_ENABLED
|
||||
rpl_neighbor_print_list("Parent switch");
|
||||
#endif /* LOG_INFO_ENABLED */
|
||||
}
|
||||
}
|
||||
|
||||
@ -261,7 +317,7 @@ update_nbr_from_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
|
||||
static void
|
||||
process_dio_from_current_dag(uip_ipaddr_t *from, rpl_dio_t *dio)
|
||||
{
|
||||
rpl_nbr_t *p;
|
||||
rpl_nbr_t *nbr;
|
||||
uint8_t last_dtsn;
|
||||
|
||||
/* Does the rank make sense at all? */
|
||||
@ -305,26 +361,25 @@ process_dio_from_current_dag(uip_ipaddr_t *from, rpl_dio_t *dio)
|
||||
}
|
||||
|
||||
/* Add neighbor to RPL neighbor table */
|
||||
p = rpl_neighbor_get_from_ipaddr(from);
|
||||
last_dtsn = p != NULL ? p->dtsn : RPL_LOLLIPOP_INIT;
|
||||
nbr = rpl_neighbor_get_from_ipaddr(from);
|
||||
last_dtsn = nbr != NULL ? nbr->dtsn : RPL_LOLLIPOP_INIT;
|
||||
|
||||
if(!update_nbr_from_dio(from, dio)) {
|
||||
LOG_ERR("neighbor table full, dropping DIO\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Init lifetime if not set yet. Refresh it at every DIO from preferred parent.
|
||||
Use same lifetime as for routes. */
|
||||
/* Init lifetime if not set yet. Refresh it at every DIO from preferred parent. */
|
||||
if(curr_instance.dag.lifetime == 0 ||
|
||||
(p != NULL && p == curr_instance.dag.preferred_parent)) {
|
||||
curr_instance.dag.lifetime =
|
||||
RPL_LIFETIME(dio->default_lifetime);
|
||||
(nbr != NULL && nbr == curr_instance.dag.preferred_parent)) {
|
||||
LOG_INFO("refreshing lifetime\n");
|
||||
curr_instance.dag.lifetime = RPL_LIFETIME(RPL_DAG_LIFETIME);
|
||||
}
|
||||
|
||||
/* If the source is our preferred parent and it increased DTSN, we increment
|
||||
* our DTSN in turn and schedule a DAO (see RFC6550 section 9.6.) */
|
||||
if(curr_instance.mop != RPL_MOP_NO_DOWNWARD_ROUTES) {
|
||||
if(p != NULL && p == curr_instance.dag.preferred_parent && rpl_lollipop_greater_than(dio->dtsn, last_dtsn)) {
|
||||
if(nbr != NULL && nbr == curr_instance.dag.preferred_parent && rpl_lollipop_greater_than(dio->dtsn, last_dtsn)) {
|
||||
RPL_LOLLIPOP_INCREMENT(curr_instance.dtsn_out);
|
||||
LOG_INFO("DTSN increment %u->%u, schedule new DAO with DTSN %u",
|
||||
last_dtsn, dio->dtsn, curr_instance.dtsn_out);
|
||||
@ -394,6 +449,7 @@ init_dag_from_dio(rpl_dio_t *dio)
|
||||
curr_instance.lifetime_unit = dio->lifetime_unit;
|
||||
|
||||
/* DAG */
|
||||
curr_instance.dag.state = DAG_INITIALIZED;
|
||||
curr_instance.dag.preference = dio->preference;
|
||||
curr_instance.dag.grounded = dio->grounded;
|
||||
curr_instance.dag.version = dio->version;
|
||||
@ -403,7 +459,7 @@ init_dag_from_dio(rpl_dio_t *dio)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int
|
||||
process_dio_join_dag(uip_ipaddr_t *from, rpl_dio_t *dio)
|
||||
process_dio_init_dag(uip_ipaddr_t *from, rpl_dio_t *dio)
|
||||
{
|
||||
/* Check MOP */
|
||||
if(dio->mop != RPL_MOP_NO_DOWNWARD_ROUTES && dio->mop != RPL_MOP_NON_STORING) {
|
||||
@ -420,16 +476,19 @@ process_dio_join_dag(uip_ipaddr_t *from, rpl_dio_t *dio)
|
||||
/* Init OF and timers */
|
||||
curr_instance.of->reset();
|
||||
rpl_timers_dio_reset("Join");
|
||||
#if RPL_WITH_PROBING
|
||||
rpl_schedule_probing();
|
||||
#endif /* RPL_WITH_PROBING */
|
||||
#if RPL_WITH_PROBING
|
||||
rpl_schedule_probing();
|
||||
#endif /* RPL_WITH_PROBING */
|
||||
/* Leave the network after RPL_DELAY_BEFORE_LEAVING in case we do not
|
||||
find a parent */
|
||||
rpl_timers_schedule_leaving();
|
||||
|
||||
LOG_INFO("joined DAG with instance ID %u, DAG ID ",
|
||||
LOG_INFO("initialized DAG with instance ID %u, DAG ID ",
|
||||
curr_instance.instance_id);
|
||||
LOG_INFO_6ADDR(&curr_instance.dag.dag_id);
|
||||
LOG_INFO_(", rank %u\n", curr_instance.dag.rank);
|
||||
|
||||
LOG_ANNOTATE("#A join=%u\n", curr_instance.dag.dag_id.u8[sizeof(curr_instance.dag.dag_id) - 1]);
|
||||
LOG_ANNOTATE("#A init=%u\n", curr_instance.dag.dag_id.u8[sizeof(curr_instance.dag.dag_id) - 1]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -438,9 +497,9 @@ void
|
||||
rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
|
||||
{
|
||||
if(!curr_instance.used && !rpl_dag_root_is_root()) {
|
||||
/* Attempt to join on this DIO */
|
||||
if(!process_dio_join_dag(from, dio)) {
|
||||
LOG_WARN("failed to join DAG");
|
||||
/* Attempt to init our DAG from this DIO */
|
||||
if(!process_dio_init_dag(from, dio)) {
|
||||
LOG_WARN("failed to init DAG");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -496,11 +555,17 @@ rpl_process_dao_ack(uint8_t sequence, uint8_t status)
|
||||
}
|
||||
/* Is this an ACK for our last DAO? */
|
||||
if(sequence == curr_instance.dag.dao_last_seqno) {
|
||||
curr_instance.dag.is_reachable = status < RPL_DAO_ACK_UNABLE_TO_ACCEPT;
|
||||
int status_ok = status < RPL_DAO_ACK_UNABLE_TO_ACCEPT;
|
||||
if(curr_instance.dag.state == DAG_JOINED && status_ok) {
|
||||
curr_instance.dag.state = DAG_REACHABLE;
|
||||
rpl_timers_dio_reset("Reachable");
|
||||
}
|
||||
|
||||
if(status >= RPL_DAO_ACK_UNABLE_TO_ACCEPT) {
|
||||
/* We got a NACK, leave the DAG */
|
||||
leave_dag("DAO-NACK");
|
||||
if(!status_ok) {
|
||||
/* We got a NACK, start poisoning and leave */
|
||||
LOG_WARN("DAO-NACK received with seqno %u, status %u, poison and leave\n",
|
||||
sequence, status);
|
||||
curr_instance.dag.state = DAG_POISONING;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -552,7 +617,7 @@ rpl_dag_init_root(uint8_t instance_id, uip_ipaddr_t *dag_id,
|
||||
version = curr_instance.dag.version;
|
||||
RPL_LOLLIPOP_INCREMENT(version);
|
||||
}
|
||||
leave_dag("init root");
|
||||
rpl_dag_leave();
|
||||
}
|
||||
|
||||
/* Init DAG and instance */
|
||||
@ -575,7 +640,7 @@ rpl_dag_init_root(uint8_t instance_id, uip_ipaddr_t *dag_id,
|
||||
curr_instance.dag.rank = ROOT_RANK;
|
||||
curr_instance.dag.lifetime = RPL_LIFETIME(RPL_INFINITE_LIFETIME);
|
||||
curr_instance.dag.dio_intcurrent = RPL_DIO_INTERVAL_MIN;
|
||||
curr_instance.dag.is_reachable = 1;
|
||||
curr_instance.dag.state = DAG_REACHABLE;
|
||||
|
||||
rpl_timers_dio_reset("Init root");
|
||||
|
||||
|
@ -50,7 +50,18 @@
|
||||
|
||||
/********** Public functions **********/
|
||||
|
||||
|
||||
/**
|
||||
* Returns a textual description of the current DAG state
|
||||
*
|
||||
* \param state The DAG state
|
||||
* \return The description string
|
||||
*/
|
||||
const char *rpl_dag_state_to_str(enum rpl_dag_state state);
|
||||
/**
|
||||
* Leaves the current DAG
|
||||
*
|
||||
*/
|
||||
void rpl_dag_leave(void);
|
||||
/**
|
||||
* A function called periodically. Used to age the DAG (decrease lifetime
|
||||
* and expire DAG accordingly)
|
||||
@ -148,6 +159,13 @@ void rpl_process_dao(uip_ipaddr_t *from, rpl_dao_t *dao);
|
||||
*/
|
||||
void rpl_process_dao_ack(uint8_t sequence, uint8_t status);
|
||||
|
||||
/**
|
||||
* Tells whether RPL is ready to advertise the DAG
|
||||
*
|
||||
* \return 1 is ready, 0 otherwise
|
||||
*/
|
||||
int rpl_dag_ready_to_advertise(void);
|
||||
|
||||
/**
|
||||
* Updates RPL internal state: selects preferred parent, updates rank & metreic
|
||||
* container, triggers control traffic accordingly and updates uIP6 internal state.
|
||||
|
@ -81,13 +81,10 @@
|
||||
|
||||
#if !RPL_MRHOF_SQUARED_ETX
|
||||
/* Hysteresis of MRHOF: the rank must differ more than PARENT_SWITCH_THRESHOLD_DIV
|
||||
* in order to switch preferred parent. Default in RFC6719: 192, eq ETX of 1.5.
|
||||
* We use a more aggressive setting: 96, eq ETX of 0.75.
|
||||
*/
|
||||
* in order to switch preferred parent. Default in RFC6719: 192, eq ETX of 1.5. */
|
||||
#define PARENT_SWITCH_THRESHOLD 192 /* Eq ETX of 1.5 */
|
||||
#else /* !RPL_MRHOF_SQUARED_ETX */
|
||||
#define PARENT_SWITCH_THRESHOLD 512 /* Eq ETX of 2. More than in the
|
||||
non-squared case because squatinf cases extra jitter. */
|
||||
#define PARENT_SWITCH_THRESHOLD 384 /* Eq ETX of sqrt(3) */
|
||||
#endif /* !RPL_MRHOF_SQUARED_ETX */
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
@ -58,6 +58,8 @@
|
||||
void RPL_CALLBACK_PARENT_SWITCH(rpl_nbr_t *old, rpl_nbr_t *new);
|
||||
#endif /* RPL_CALLBACK_PARENT_SWITCH */
|
||||
|
||||
static rpl_nbr_t * best_parent(int fresh_only);
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Per-neighbor RPL information */
|
||||
NBR_TABLE_GLOBAL(rpl_nbr_t, rpl_neighbors);
|
||||
@ -70,8 +72,7 @@ acceptable_rank(rpl_rank_t rank)
|
||||
return rank != RPL_INFINITE_RANK
|
||||
&& rank >= ROOT_RANK
|
||||
&& ((curr_instance.max_rankinc == 0) ||
|
||||
DAG_RANK(rank) <=
|
||||
DAG_RANK(curr_instance.dag.lowest_rank + curr_instance.max_rankinc));
|
||||
rank <= curr_instance.dag.lowest_rank + curr_instance.max_rankinc);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
@ -81,11 +82,13 @@ rpl_neighbor_print_list(const char *str)
|
||||
int curr_dio_interval = curr_instance.dag.dio_intcurrent;
|
||||
int curr_rank = curr_instance.dag.rank;
|
||||
rpl_nbr_t *nbr = nbr_table_head(rpl_neighbors);
|
||||
rpl_nbr_t *best = best_parent(0);
|
||||
clock_time_t clock_now = clock_time();
|
||||
|
||||
LOG_INFO("nbr: own state, addr ");
|
||||
LOG_INFO_6ADDR(rpl_get_global_address());
|
||||
LOG_INFO_(" MOP %u OCP %u rank %u max-rank %u, dioint %u, DS6 nbr count %u (%s)\n",
|
||||
LOG_INFO_(", DAG state: %s, MOP %u OCP %u rank %u max-rank %u, dioint %u, DS6 nbr count %u (%s)\n",
|
||||
rpl_dag_state_to_str(curr_instance.dag.state),
|
||||
curr_instance.mop, curr_instance.of->ocp, curr_rank,
|
||||
curr_instance.max_rankinc != 0 ? curr_instance.dag.lowest_rank + curr_instance.max_rankinc : 0xffff,
|
||||
curr_dio_interval, uip_ds6_nbr_num(), str);
|
||||
@ -93,12 +96,13 @@ rpl_neighbor_print_list(const char *str)
|
||||
const struct link_stats *stats = rpl_neighbor_get_link_stats(nbr);
|
||||
LOG_INFO("nbr: ");
|
||||
LOG_INFO_6ADDR(rpl_neighbor_get_ipaddr(nbr));
|
||||
LOG_INFO_(" %5u, %5u => %5u -- %2u %c%c%c%c",
|
||||
LOG_INFO_(" %5u, %5u => %5u -- %2u %c%c%c%c%c",
|
||||
nbr->rank,
|
||||
rpl_neighbor_get_link_metric(nbr),
|
||||
rpl_neighbor_rank_via_nbr(nbr),
|
||||
stats != NULL ? stats->freshness : 0,
|
||||
(nbr->rank == ROOT_RANK) ? 'r' : ' ',
|
||||
nbr == best ? 'b' : ' ',
|
||||
(acceptable_rank(rpl_neighbor_rank_via_nbr(nbr)) && curr_instance.of->nbr_is_acceptable_parent(nbr)) ? 'a' : ' ',
|
||||
link_stats_is_fresh(stats) ? 'f' : ' ',
|
||||
nbr == curr_instance.dag.preferred_parent ? 'p' : ' '
|
||||
@ -218,7 +222,7 @@ rpl_neighbor_is_parent(rpl_nbr_t *nbr)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
rpl_neighbor_set_preferred(rpl_nbr_t *nbr)
|
||||
rpl_neighbor_set_preferred_parent(rpl_nbr_t *nbr)
|
||||
{
|
||||
if(curr_instance.dag.preferred_parent != nbr) {
|
||||
LOG_INFO("parent switch: ");
|
||||
@ -331,12 +335,15 @@ rpl_neighbor_select_best(void)
|
||||
} else {
|
||||
rpl_nbr_t *best_fresh;
|
||||
|
||||
/* The best is not fresh. Probe it. */
|
||||
curr_instance.dag.urgent_probing_target = best;
|
||||
LOG_WARN("best parent is not fresh, schedule urgent probing to ");
|
||||
LOG_WARN_6ADDR(rpl_neighbor_get_ipaddr(best));
|
||||
LOG_WARN_("\n");
|
||||
rpl_schedule_probing();
|
||||
/* The best is not fresh. Probe it (unless there is already an urgent
|
||||
probing target). We will be called back after the probing anyway. */
|
||||
if(curr_instance.dag.urgent_probing_target == NULL) {
|
||||
LOG_WARN("best parent is not fresh, schedule urgent probing to ");
|
||||
LOG_WARN_6ADDR(rpl_neighbor_get_ipaddr(best));
|
||||
LOG_WARN_("\n");
|
||||
curr_instance.dag.urgent_probing_target = best;
|
||||
rpl_schedule_probing();
|
||||
}
|
||||
|
||||
/* Look for the best fresh parent. */
|
||||
best_fresh = best_parent(1);
|
||||
|
@ -83,7 +83,7 @@ int rpl_neighbor_is_parent(rpl_nbr_t *nbr);
|
||||
*
|
||||
* \param nbr The new preferred parent
|
||||
*/
|
||||
void rpl_neighbor_set_preferred(rpl_nbr_t *nbr);
|
||||
void rpl_neighbor_set_preferred_parent(rpl_nbr_t *nbr);
|
||||
|
||||
/**
|
||||
* Tells wether we have fresh link information towards a given neighbor
|
||||
|
@ -92,7 +92,7 @@ static struct ctimer periodic_timer; /* Not part of a DAG because used for gener
|
||||
void
|
||||
rpl_timers_schedule_periodic_dis(void)
|
||||
{
|
||||
if(etimer_expired(&dis_timer.etimer)) {
|
||||
if(ctimer_expired(&dis_timer)) {
|
||||
clock_time_t expiration_time = RPL_DIS_INTERVAL / 2 + (random_rand() % (RPL_DIS_INTERVAL));
|
||||
ctimer_set(&dis_timer, expiration_time, handle_dis_timer, NULL);
|
||||
}
|
||||
@ -149,7 +149,7 @@ new_dio_interval(void)
|
||||
void
|
||||
rpl_timers_dio_reset(const char *str)
|
||||
{
|
||||
if(curr_instance.used) {
|
||||
if(rpl_dag_ready_to_advertise()) {
|
||||
LOG_INFO("reset DIO timer (%s)\n", str);
|
||||
#if !RPL_LEAF_ONLY
|
||||
curr_instance.dag.dio_counter = 0;
|
||||
@ -162,8 +162,8 @@ rpl_timers_dio_reset(const char *str)
|
||||
static void
|
||||
handle_dio_timer(void *ptr)
|
||||
{
|
||||
if(!curr_instance.used) {
|
||||
return; /* We will be scheduled again at join time */
|
||||
if(!rpl_dag_ready_to_advertise()) {
|
||||
return; /* We will be scheduled again later */
|
||||
}
|
||||
|
||||
if(curr_instance.dag.dio_send) {
|
||||
@ -206,6 +206,7 @@ rpl_timers_schedule_unicast_dio(rpl_nbr_t *target)
|
||||
handle_unicast_dio_timer, NULL);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
handle_unicast_dio_timer(void *ptr)
|
||||
{
|
||||
@ -294,7 +295,10 @@ handle_dao_timer(void *ptr)
|
||||
schedule_dao_retransmission();
|
||||
#else /* RPL_WITH_DAO_ACK */
|
||||
/* No DAO-ACK: assume we are reachable as soon as we send a DAO */
|
||||
curr_instance.dag.is_reachable = 1;
|
||||
if(curr_instance.dag.state == DAG_JOINED) {
|
||||
curr_instance.dag.state = DAG_REACHABLE;
|
||||
}
|
||||
rpl_timers_dio_reset("Reachable");
|
||||
#endif /* !RPL_WITH_DAO_ACK */
|
||||
|
||||
curr_instance.dag.dao_last_seqno = curr_instance.dag.dao_curr_seqno;
|
||||
@ -447,6 +451,36 @@ rpl_schedule_probing(void)
|
||||
}
|
||||
#endif /* RPL_WITH_PROBING */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*------------------------------- Leaving-- -------------------------------- */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
handle_leaving_timer(void *ptr)
|
||||
{
|
||||
if(curr_instance.used) {
|
||||
rpl_dag_leave();
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
rpl_timers_unschedule_leaving(void)
|
||||
{
|
||||
if(curr_instance.used) {
|
||||
if(!ctimer_expired(&curr_instance.dag.leave)) {
|
||||
ctimer_stop(&curr_instance.dag.leave);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
rpl_timers_schedule_leaving(void)
|
||||
{
|
||||
if(curr_instance.used) {
|
||||
if(ctimer_expired(&curr_instance.dag.leave)) {
|
||||
ctimer_set(&curr_instance.dag.leave, PERIODIC_DELAY, handle_leaving_timer, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*------------------------------- Periodic---------------------------------- */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
@ -482,6 +516,7 @@ rpl_timers_stop_dag_timers(void)
|
||||
{
|
||||
/* Stop all timers related to the DAG */
|
||||
ctimer_stop(&curr_instance.dag.state_update);
|
||||
ctimer_stop(&curr_instance.dag.leave);
|
||||
ctimer_stop(&curr_instance.dag.dio_timer);
|
||||
ctimer_stop(&curr_instance.dag.unicast_dio_timer);
|
||||
ctimer_stop(&curr_instance.dag.dao_timer);
|
||||
|
@ -56,6 +56,16 @@
|
||||
*/
|
||||
void rpl_timers_schedule_periodic_dis(void);
|
||||
|
||||
/**
|
||||
* Cancel scheduled leaving if any
|
||||
*/
|
||||
void rpl_timers_unschedule_leaving(void);
|
||||
|
||||
/**
|
||||
* Schedule leaving after RPL_DELAY_BEFORE_LEAVING
|
||||
*/
|
||||
void rpl_timers_schedule_leaving(void);
|
||||
|
||||
/**
|
||||
* Initialize rpl-timers module
|
||||
*/
|
||||
|
@ -169,6 +169,13 @@ typedef struct rpl_nbr rpl_nbr_t;
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Directed Acyclic Graph */
|
||||
enum rpl_dag_state {
|
||||
DAG_INITIALIZED,
|
||||
DAG_JOINED,
|
||||
DAG_REACHABLE,
|
||||
DAG_POISONING
|
||||
};
|
||||
|
||||
struct rpl_dag {
|
||||
uip_ipaddr_t dag_id;
|
||||
rpl_prefix_t prefix_info;
|
||||
@ -186,11 +193,12 @@ struct rpl_dag {
|
||||
uint8_t dao_last_acked_seqno; /* the last seqno we got an ACK for */
|
||||
uint8_t dao_curr_seqno; /* the node's current DAO seqno (sent or to be sent) */
|
||||
uint8_t dao_transmissions; /* the number of transmissions for the current DAO */
|
||||
uint8_t is_reachable; /* is the node reachable via a downward route? */
|
||||
enum rpl_dag_state state;
|
||||
|
||||
/* Timers */
|
||||
clock_time_t dio_next_delay; /* delay for completion of dio interval */
|
||||
struct ctimer state_update;
|
||||
struct ctimer leave;
|
||||
struct ctimer dio_timer;
|
||||
struct ctimer unicast_dio_timer;
|
||||
struct ctimer dao_timer;
|
||||
|
@ -104,7 +104,7 @@ rpl_link_neighbor_callback(const linkaddr_t *addr, int status, int numtx)
|
||||
int
|
||||
rpl_is_reachable(void)
|
||||
{
|
||||
return curr_instance.used && curr_instance.dag.is_reachable;
|
||||
return curr_instance.used && curr_instance.dag.state == DAG_REACHABLE;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
|
Loading…
Reference in New Issue
Block a user