45 #include "net/routing/rpl-lite/rpl.h" 47 #include "net/nbr-table.h" 48 #include "net/link-stats.h" 52 #define LOG_MODULE "RPL" 53 #define LOG_LEVEL LOG_LEVEL_RPL 57 static rpl_of_t *
const objective_functions[] = RPL_SUPPORTED_OFS;
58 static int init_dag_from_dio(rpl_dio_t *dio);
85 if(curr_instance.used && ipaddr != NULL) {
95 LOG_INFO(
"leaving DAG ");
96 LOG_INFO_6ADDR(&curr_instance.dag.dag_id);
97 LOG_INFO_(
", instance %u\n", curr_instance.instance_id);
101 RPL_LOLLIPOP_INCREMENT(curr_instance.dag.dao_curr_seqno);
116 if((curr_instance.dag.prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS)) {
121 curr_instance.used = 0;
127 curr_instance.dag.state = DAG_POISONING;
134 if(curr_instance.used) {
135 if(curr_instance.dag.lifetime !=
RPL_LIFETIME(RPL_INFINITE_LIFETIME)) {
136 curr_instance.dag.lifetime =
137 curr_instance.dag.lifetime > seconds ? curr_instance.dag.lifetime - seconds : 0;
138 if(curr_instance.dag.lifetime == 0) {
139 LOG_WARN(
"DAG expired, poison and leave\n");
140 curr_instance.dag.state = DAG_POISONING;
142 }
else if(curr_instance.dag.lifetime < 300 && curr_instance.dag.preferred_parent != NULL) {
144 LOG_WARN(
"DAG expiring in %u seconds, send DIS to preferred parent\n", (
unsigned)curr_instance.dag.lifetime);
154 return curr_instance.used
155 && uip_ipaddr_prefixcmp(&curr_instance.dag.dag_id, addr, curr_instance.dag.prefix_info.length);
161 return curr_instance.used ? &curr_instance : NULL;
167 return curr_instance.used ? &curr_instance.dag : NULL;
171 find_objective_function(rpl_ocp_t ocp)
174 for(i = 0; i <
sizeof(objective_functions) /
sizeof(objective_functions[0]); i++) {
175 if(objective_functions[i]->ocp == ocp) {
176 return objective_functions[i];
187 RPL_LOLLIPOP_INCREMENT(curr_instance.dtsn_out);
189 LOG_WARN(
"incremented DTSN (%s), current %u\n",
190 str, curr_instance.dtsn_out);
191 if(LOG_INFO_ENABLED) {
201 RPL_LOLLIPOP_INCREMENT(curr_instance.dag.version);
202 curr_instance.dtsn_out = RPL_LOLLIPOP_INIT;
204 LOG_WARN(
"initiating global repair (%s), version %u, rank %u\n",
205 str, curr_instance.dag.version, curr_instance.dag.rank);
206 if(LOG_INFO_ENABLED) {
216 global_repair_non_root(rpl_dio_t *dio)
219 LOG_WARN(
"participating in global repair, version %u, rank %u\n",
220 dio->version, curr_instance.dag.rank);
221 if(LOG_INFO_ENABLED) {
226 init_dag_from_dio(dio);
234 if(curr_instance.used) {
235 LOG_WARN(
"local repair (%s)\n", str);
237 curr_instance.dag.state = DAG_INITIALIZED;
239 curr_instance.of->reset();
249 if(curr_instance.mop == RPL_MOP_NO_DOWNWARD_ROUTES) {
250 return curr_instance.used && curr_instance.dag.state >= DAG_INITIALIZED;
252 return curr_instance.used && curr_instance.dag.state >= DAG_REACHABLE;
262 if(!curr_instance.used) {
266 old_rank = curr_instance.dag.rank;
270 if(curr_instance.dag.state == DAG_POISONING) {
272 curr_instance.dag.rank = RPL_INFINITE_RANK;
273 if(old_rank != RPL_INFINITE_RANK) {
275 LOG_WARN(
"poisoning and leaving after a delay\n");
280 rpl_nbr_t *old_parent = curr_instance.dag.preferred_parent;
289 nbr = nbr_table_head(rpl_neighbors);
294 if(nbr->better_parent_since == 0) {
298 nbr->better_parent_since = 0;
300 nbr = nbr_table_next(rpl_neighbors, nbr);
303 if(old_parent == NULL || curr_instance.dag.rank < curr_instance.dag.lowest_rank) {
306 curr_instance.dag.lowest_rank = curr_instance.dag.rank;
310 if(curr_instance.dag.last_advertised_rank != RPL_INFINITE_RANK
311 && curr_instance.dag.rank != RPL_INFINITE_RANK
312 && ABS((int32_t)curr_instance.dag.rank - curr_instance.dag.last_advertised_rank) > RPL_SIGNIFICANT_CHANGE_THRESHOLD) {
313 LOG_WARN(
"significant rank update %u->%u\n",
314 curr_instance.dag.last_advertised_rank, curr_instance.dag.rank);
316 curr_instance.dag.last_advertised_rank = curr_instance.dag.rank;
321 if(curr_instance.dag.preferred_parent != old_parent) {
323 if(old_parent == NULL) {
324 curr_instance.dag.state = DAG_JOINED;
326 LOG_WARN(
"found parent: ");
328 LOG_WARN_(
", staying in DAG\n");
333 if(curr_instance.dag.preferred_parent != NULL) {
337 curr_instance.dag.state = DAG_INITIALIZED;
338 LOG_WARN(
"no parent, scheduling periodic DIS, will leave if no parent is found\n");
344 if(LOG_INFO_ENABLED) {
351 curr_instance.of->update_metric_container();
355 update_nbr_from_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
358 const uip_lladdr_t *lladdr;
365 lladdr = uip_ds6_nbr_lladdr_from_ipaddr(from);
371 nbr = nbr_table_add_lladdr(rpl_neighbors, (linkaddr_t *)lladdr,
372 NBR_TABLE_REASON_RPL_DIO, dio);
374 LOG_ERR(
"failed to add neighbor\n");
380 nbr->rank = dio->rank;
381 nbr->dtsn = dio->dtsn;
383 memcpy(&nbr->mc, &dio->mc,
sizeof(nbr->mc));
390 process_dio_from_current_dag(uip_ipaddr_t *from, rpl_dio_t *dio)
415 if(dio->rank != RPL_INFINITE_RANK) {
416 curr_instance.dag.dio_counter++;
423 if(curr_instance.dag.rank ==
ROOT_RANK) {
425 LOG_ERR(
"inconsistent DIO version (current: %u, received: %u), initiate global repair\n",
426 curr_instance.dag.version, dio->version);
428 curr_instance.dag.version = dio->version;
431 LOG_WARN(
"new DIO version (current: %u, received: %u), apply global repair\n",
432 curr_instance.dag.version, dio->version);
433 global_repair_non_root(dio);
439 LOG_ERR(
"IPv6 cache full, dropping DIO\n");
445 last_dtsn = nbr != NULL ? nbr->dtsn : RPL_LOLLIPOP_INIT;
447 if(!update_nbr_from_dio(from, dio)) {
448 LOG_ERR(
"neighbor table full, dropping DIO\n");
453 if(curr_instance.dag.lifetime == 0 ||
454 (nbr != NULL && nbr == curr_instance.dag.preferred_parent)) {
455 LOG_INFO(
"refreshing lifetime\n");
456 curr_instance.dag.lifetime =
RPL_LIFETIME(RPL_DAG_LIFETIME);
461 if(curr_instance.mop != RPL_MOP_NO_DOWNWARD_ROUTES) {
463 RPL_LOLLIPOP_INCREMENT(curr_instance.dtsn_out);
464 LOG_WARN(
"DTSN increment %u->%u, schedule new DAO with DTSN %u\n",
465 last_dtsn, dio->dtsn, curr_instance.dtsn_out);
472 init_dag(uint8_t instance_id, uip_ipaddr_t *dag_id, rpl_ocp_t ocp,
473 uip_ipaddr_t *prefix,
unsigned prefix_len, uint8_t prefix_flags)
477 memset(&curr_instance, 0,
sizeof(curr_instance));
480 of = find_objective_function(ocp);
482 LOG_ERR(
"ignoring DIO with an unsupported OF: %u\n", ocp);
488 LOG_ERR(
"failed to set prefix\n");
493 curr_instance.instance_id = instance_id;
494 curr_instance.of = of;
495 curr_instance.dtsn_out = RPL_LOLLIPOP_INIT;
496 curr_instance.used = 1;
499 curr_instance.dag.rank = RPL_INFINITE_RANK;
500 curr_instance.dag.last_advertised_rank = RPL_INFINITE_RANK;
501 curr_instance.dag.lowest_rank = RPL_INFINITE_RANK;
502 curr_instance.dag.dao_last_seqno = RPL_LOLLIPOP_INIT;
503 curr_instance.dag.dao_last_acked_seqno = RPL_LOLLIPOP_INIT;
504 curr_instance.dag.dao_curr_seqno = RPL_LOLLIPOP_INIT;
505 memcpy(&curr_instance.dag.dag_id, dag_id,
sizeof(curr_instance.dag.dag_id));
511 init_dag_from_dio(rpl_dio_t *dio)
513 if(!init_dag(dio->instance_id, &dio->dag_id, dio->ocp,
514 &dio->prefix_info.prefix, dio->prefix_info.length, dio->prefix_info.flags)) {
519 curr_instance.mop = dio->mop;
520 curr_instance.mc.type = dio->mc.type;
521 curr_instance.mc.flags = dio->mc.flags;
522 curr_instance.mc.aggr = dio->mc.aggr;
523 curr_instance.mc.prec = dio->mc.prec;
524 curr_instance.max_rankinc = dio->dag_max_rankinc;
525 curr_instance.min_hoprankinc = dio->dag_min_hoprankinc;
526 curr_instance.dio_intdoubl = dio->dag_intdoubl;
527 curr_instance.dio_intmin = dio->dag_intmin;
528 curr_instance.dio_redundancy = dio->dag_redund;
529 curr_instance.default_lifetime = dio->default_lifetime;
530 curr_instance.lifetime_unit = dio->lifetime_unit;
533 curr_instance.dag.state = DAG_INITIALIZED;
534 curr_instance.dag.preference = dio->preference;
535 curr_instance.dag.grounded = dio->grounded;
536 curr_instance.dag.version = dio->version;
537 curr_instance.dag.dio_intcurrent = dio->dag_intmin;
543 process_dio_init_dag(uip_ipaddr_t *from, rpl_dio_t *dio)
546 if(dio->mop != RPL_MOP_NO_DOWNWARD_ROUTES && dio->mop != RPL_MOP_NON_STORING) {
547 LOG_WARN(
"ignoring DIO with an unsupported MOP: %d\n", dio->mop);
552 if(!init_dag_from_dio(dio)) {
553 LOG_WARN(
"failed to initialize DAG\n");
558 curr_instance.of->reset();
565 LOG_INFO(
"initialized DAG with instance ID %u, DAG ID ",
566 curr_instance.instance_id);
567 LOG_INFO_6ADDR(&curr_instance.dag.dag_id);
568 LOG_INFO_(
", prexix ");
569 LOG_INFO_6ADDR(&dio->prefix_info.prefix);
570 LOG_INFO_(
"/%u, rank %u\n", dio->prefix_info.length, curr_instance.dag.rank);
572 LOG_ANNOTATE(
"#A init=%u\n", curr_instance.dag.dag_id.u8[
sizeof(curr_instance.dag.dag_id) - 1]);
574 LOG_WARN(
"just joined, no parent yet, setting timer for leaving\n");
585 if(!process_dio_init_dag(from, dio)) {
586 LOG_WARN(
"failed to init DAG\n");
591 if(curr_instance.used
592 && curr_instance.instance_id == dio->instance_id
593 && uip_ipaddr_cmp(&curr_instance.dag.dag_id, &dio->dag_id)) {
594 process_dio_from_current_dag(from, dio);
607 LOG_INFO(
"unicast DIS, reply to sender\n");
616 if(dao->lifetime == 0) {
620 LOG_ERR(
"failed to add link on incoming DAO\n");
626 if(dao->flags & RPL_DAO_K_FLAG) {
638 curr_instance.dag.dao_last_acked_seqno = sequence;
641 if(sequence == curr_instance.dag.dao_last_seqno) {
642 int status_ok = status < RPL_DAO_ACK_UNABLE_TO_ACCEPT;
643 if(curr_instance.dag.state == DAG_JOINED && status_ok) {
644 curr_instance.dag.state = DAG_REACHABLE;
650 LOG_WARN(
"DAO-NACK received with seqno %u, status %u, poison and leave\n",
652 curr_instance.dag.state = DAG_POISONING;
664 if(rank_error_signaled) {
665 #if RPL_LOOP_ERROR_DROP 668 LOG_WARN(
"rank error and loop detected, dropping\n");
677 if(rank_error_signaled) {
681 sender->rank = sender_rank;
693 uip_ipaddr_t *prefix,
unsigned prefix_len, uint8_t prefix_flags)
695 uint8_t version = RPL_LOLLIPOP_INIT;
698 if(curr_instance.used) {
700 if(uip_ipaddr_cmp(&curr_instance.dag.dag_id, dag_id)) {
701 version = curr_instance.dag.version;
702 RPL_LOLLIPOP_INCREMENT(version);
708 init_dag(instance_id, dag_id, RPL_OF_OCP, prefix, prefix_len, prefix_flags);
711 curr_instance.mop = RPL_MOP_DEFAULT;
712 curr_instance.max_rankinc = RPL_MAX_RANKINC;
713 curr_instance.min_hoprankinc = RPL_MIN_HOPRANKINC;
714 curr_instance.dio_intdoubl = RPL_DIO_INTERVAL_DOUBLINGS;
715 curr_instance.dio_intmin = RPL_DIO_INTERVAL_MIN;
716 curr_instance.dio_redundancy = RPL_DIO_REDUNDANCY;
717 curr_instance.default_lifetime = RPL_DEFAULT_LIFETIME;
718 curr_instance.lifetime_unit = RPL_DEFAULT_LIFETIME_UNIT;
721 curr_instance.dag.preference = RPL_PREFERENCE;
722 curr_instance.dag.grounded = RPL_GROUNDED;
723 curr_instance.dag.version = version;
725 curr_instance.dag.lifetime =
RPL_LIFETIME(RPL_INFINITE_LIFETIME);
726 curr_instance.dag.dio_intcurrent = RPL_DIO_INTERVAL_MIN;
727 curr_instance.dag.state = DAG_REACHABLE;
731 LOG_INFO(
"created DAG with instance ID %u, DAG ID ",
732 curr_instance.instance_id);
733 LOG_INFO_6ADDR(&curr_instance.dag.dag_id);
734 LOG_INFO_(
", rank %u\n", curr_instance.dag.rank);
736 LOG_ANNOTATE(
"#A root=%u\n", curr_instance.dag.dag_id.u8[
sizeof(curr_instance.dag.dag_id) - 1]);
742 memset(&curr_instance, 0,
sizeof(curr_instance));
static uip_ipaddr_t ipaddr
Pointer to prefix information option in uip_buf.
void rpl_dag_poison_and_leave(void)
Start poisoning and leave the DAG after a delay.
uip_ipaddr_t * rpl_neighbor_get_ipaddr(rpl_nbr_t *nbr)
Returns a neighbor's (link-local) IPv6 address.
static uip_ds6_nbr_t * nbr
Pointer to llao option in uip_buf.
void rpl_process_dao(uip_ipaddr_t *from, rpl_dao_t *dao)
Processes incoming DAO.
void rpl_timers_schedule_unicast_dio(rpl_nbr_t *target)
Schedule unicast DIO with no delay.
#define ROOT_RANK
Rank of a root node.
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.
int rpl_lollipop_greater_than(int a, int b)
Greater-than function for a lollipop counter.
void rpl_global_repair(const char *str)
Triggers a RPL global repair.
void rpl_neighbor_remove_all(void)
Empty the RPL neighbor table.
rpl_nbr_t * rpl_neighbor_get_from_ipaddr(uip_ipaddr_t *addr)
Returns a neighbor from its link-local IPv6 address.
void uip_sr_free_all(void)
Deallocate all neighbors.
int rpl_is_addr_in_our_dag(const uip_ipaddr_t *addr)
Tells whether a given global IPv6 address is in our current DAG.
#define RPL_LIFETIME(lifetime)
Compute lifetime, accounting for the lifetime unit.
void rpl_dag_init_root(uint8_t instance_id, uip_ipaddr_t *dag_id, uip_ipaddr_t *prefix, unsigned prefix_len, uint8_t prefix_flags)
Initializes DAG internal structure for a root node.
void uip_sr_expire_parent(void *graph, const uip_ipaddr_t *child, const uip_ipaddr_t *parent)
Expires a given child-parent link.
int rpl_dag_root_is_root(void)
Tells whether we are DAG root or not.
void rpl_timers_schedule_dao_ack(uip_ipaddr_t *target, uint16_t sequence)
Schedule a DAO-ACK with no delay.
void rpl_icmp6_dao_output(uint8_t lifetime)
Creates an ICMPv6 DAO packet and sends it to the root, advertising the current preferred parent...
void rpl_process_dao_ack(uint8_t sequence, uint8_t status)
Processes incoming DAO-ACK.
API for RPL objective functions (OF)
const char * rpl_dag_state_to_str(enum rpl_dag_state state)
Returns a textual description of the current DAG state.
int rpl_set_prefix_from_addr(uip_ipaddr_t *addr, unsigned len, uint8_t flags)
Set prefix from an IPv6 address.
void rpl_timers_schedule_state_update(void)
Schedule a state update ASAP.
void rpl_timers_dio_reset(const char *str)
Reset DIO Trickle timer.
void rpl_timers_unschedule_leaving(void)
Cancel scheduled leaving if any.
void rpl_timers_stop_dag_timers(void)
Stop all timers related to the DAG.
void rpl_dag_leave(void)
Leaves the current DAG.
void rpl_process_dis(uip_ipaddr_t *from, int is_multicast)
Processes incoming DIS.
rpl_dag_state
RPL DAG states.
All information related to a RPL neighbor.
rpl_dag_t * rpl_get_any_dag(void)
Returns pointer to any DAG (for compatibility with legagy RPL code)
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
clock_time_t clock_time(void)
Get the current clock time.
int rpl_dag_ready_to_advertise(void)
Tells whether RPL is ready to advertise the DAG.
void rpl_timers_schedule_periodic_dis(void)
Schedule periodic DIS with a random delay based on RPL_DIS_INTERVAL, until we join a DAG...
uip_ds6_nbr_t * rpl_icmp6_update_nbr_table(uip_ipaddr_t *from, nbr_table_reason_t reason, void *data)
Updates IPv6 neighbor cache on incoming link-local RPL ICMPv6 messages.
void rpl_timers_schedule_dao(void)
Schedule a DAO with random delay based on RPL_DAO_DELAY.
void rpl_dag_periodic(unsigned seconds)
A function called periodically.
void rpl_neighbor_print_list(const char *str)
Prints a summary of all RPL neighbors and their properties.
void rpl_refresh_routes(const char *str)
Triggers a route fresh via DTSN increment.
void rpl_dag_update_state(void)
Updates RPL internal state: selects preferred parent, updates rank & metreic container, triggers control traffic accordingly and updates uIP6 internal state.
void rpl_timers_schedule_leaving(void)
Schedule leaving after RPL_DELAY_BEFORE_LEAVING.
int rpl_dag_get_root_ipaddr(uip_ipaddr_t *ipaddr)
Returns the IPv6 address of the RPL DAG root, if any.
uip_sr_node_t * uip_sr_update_node(void *graph, const uip_ipaddr_t *child, const uip_ipaddr_t *parent, uint32_t lifetime)
Updates a child-parent link.
void rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
Processes incoming DIO.
int rpl_process_hbh(rpl_nbr_t *sender, uint16_t sender_rank, int loop_detected, int rank_error_signaled)
Processes Hop-by-Hop (HBH) Extension Header of a packet currently being forwrded. ...
void rpl_timers_unschedule_state_update(void)
Cancelled any scheduled state update.
rpl_rank_t rpl_neighbor_rank_via_nbr(rpl_nbr_t *nbr)
Returns our rank if selecting a given parent as preferred parent.
void rpl_local_repair(const char *str)
Triggers a RPL local repair.
void rpl_reset_prefix(rpl_prefix_t *last_prefix)
Removes current prefx.
void rpl_neighbor_set_preferred_parent(rpl_nbr_t *nbr)
Set current RPL preferred parent and update DS6 default route accordingly.
void rpl_icmp6_dio_output(uip_ipaddr_t *uc_addr)
Creates an ICMPv6 DIO packet and sends it.
Header file for the logging system
rpl_nbr_t * rpl_neighbor_select_best(void)
Returns the best candidate for preferred parent.
rpl_instance_t * rpl_get_default_instance(void)
Returns pointer to the default instance (for compatibility with legagy RPL code)
void rpl_dag_init(void)
Initializes rpl-dag module.
void rpl_icmp6_dis_output(uip_ipaddr_t *addr)
Creates an ICMPv6 DIS packet and sends it.
void rpl_schedule_probing(void)
Schedule probing with delay RPL_PROBING_DELAY_FUNC()