1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-17 18:12:46 +01:00

rpl: RPL/Trickle with only *one* thread

This PR proposes an approach to reduce the thread count of RPL.

The current RPL/Trickle stack needs about 5 threads to handle tasks
like updating the trickle timer, routing entries and the transmission of
DAOs.

This PR modifies RPL to use only one thread with a looped `msg_recv()` call.
The message is then multiplexed to the right task.
This commit is contained in:
Cenk Gündoğan 2014-10-14 08:14:45 +02:00
parent c4d4458651
commit c4b01b87bc
15 changed files with 518 additions and 438 deletions

View File

@ -32,6 +32,7 @@ ifneq (,$(filter sixlowborder,$(USEMODULE)))
endif endif
ifneq (,$(filter rpl,$(USEMODULE))) ifneq (,$(filter rpl,$(USEMODULE)))
USEMODULE += trickle
USEMODULE += routing USEMODULE += routing
endif endif

View File

@ -71,6 +71,9 @@ endif
ifneq (,$(filter netapi,$(USEMODULE))) ifneq (,$(filter netapi,$(USEMODULE)))
DIRS += net/crosslayer/netapi DIRS += net/crosslayer/netapi
endif endif
ifneq (,$(filter trickle,$(USEMODULE)))
DIRS += trickle
endif
DIRS += $(dir $(wildcard $(addsuffix /Makefile, ${USEMODULE}))) DIRS += $(dir $(wildcard $(addsuffix /Makefile, ${USEMODULE})))

114
sys/include/trickle.h Normal file
View File

@ -0,0 +1,114 @@
/*
* Trickle constants and prototypes
*
* Copyright (C) 2013, 2014 INRIA.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup sys_trickle Trickle Timer
* @ingroup sys
* @{
*/
/**
* @file trickle.h
* @brief Implementation of a generic Trickle Algorithm (RFC 6206)
*
* @author Eric Engel <eric.engel@fu-berlin.de>
* @author Cenk Gündoğan <cnkgndgn@gmail.com>
*/
#ifndef _TRICKLE_H
#define _TRICKLE_H
#ifdef __cplusplus
extern "C" {
#endif
#include "vtimer.h"
#include "thread.h"
/** @brief a generic callback function with arguments that is called by trickle periodically */
typedef struct {
void (*func)(void *); /**< a generic callback function pointer */
void *args; /**< a generic parameter for the callback function pointer */
} trickle_callback_t;
/** @brief all state variables for a trickle timer */
typedef struct {
uint8_t k; /**< redundancy constant */
uint32_t Imin; /**< minimum interval size */
uint8_t Imax; /**< maximum interval size, described as a number of doublings */
uint32_t I; /**< current interval size */
uint32_t t; /**< time within the current interval */
uint16_t c; /**< counter */
kernel_pid_t pid; /**< pid of trickles target thread */
trickle_callback_t callback; /**< the callback function and parameter that trickle is calling
after each interval */
uint16_t interval_msg_type; /**< the msg_t.type that trickle should use after an interval */
timex_t msg_interval_time; /**< interval represented as timex_t */
vtimer_t msg_interval_timer; /**< vtimer to send a msg_t to the target thread for a new interval */
uint16_t callback_msg_type; /**< the msg_t.type that trickle should use after a callback */
timex_t msg_callback_time; /**< callback interval represented as timex_t */
vtimer_t msg_callback_timer; /**< vtimer to send a msg_t to the target thread for a callback */
} trickle_t;
/**
* @brief resets the trickle timer
*
* @param[in] trickle the trickle timer
*/
void trickle_reset_timer(trickle_t *trickle);
/**
* @brief start the trickle timer
*
* @param[in] pid target thread
* @param[in] trickle trickle timer
* @param[in] interval_msg_type msg_t.type for interval messages
* @param[in] callback_msg_type msg_t.type for callback messages
* @param[in] Imin minimum interval
* @param[in] Imax maximum interval
* @param[in] k redundancy constant
*/
void trickle_start(kernel_pid_t pid, trickle_t *trickle, uint16_t interval_msg_type,
uint16_t callback_msg_type, uint32_t Imin, uint8_t Imax, uint8_t k);
/**
* @brief stops the trickle timer
*
* @param[in] trickle trickle timer
*/
void trickle_stop(trickle_t *trickle);
/**
* @brief increments the counter by one
*
* @param[in] trickle trickle timer
*/
void trickle_increment_counter(trickle_t *trickle);
/**
* @brief is called after the interval is over and calculates the next interval
*
* @param[in] trickle trickle timer
*/
void trickle_interval(trickle_t *trickle);
/**
* @brief is called after the callback interval is over and calls the callback function
*
* @param[in] trickle trickle timer
*/
void trickle_callback(trickle_t *trickle);
#ifdef __cplusplus
}
#endif
#endif /* _TRICKLE_H */
/** @} */

View File

@ -32,12 +32,21 @@ extern "C" {
#define RPL_STORING_MODE_NO_MC 0x02 #define RPL_STORING_MODE_NO_MC 0x02
#define RPL_STORING_MODE_MC 0x03 #define RPL_STORING_MODE_MC 0x03
/* ICMP type */
#define RPL_SEQUENCE_WINDOW 16 #define RPL_SEQUENCE_WINDOW 16
#define ICMP_CODE_DIS 0x00 /* RPL Message type */
#define ICMP_CODE_DIO 0x01 enum RPL_MSG_CODE {
#define ICMP_CODE_DAO 0x02 ICMP_CODE_DIS = 0,
#define ICMP_CODE_DAO_ACK 0x03 ICMP_CODE_DIO,
ICMP_CODE_DAO,
ICMP_CODE_DAO_ACK,
/* put all ICMP codes before the end marker */
ICMP_CODE_END,
RPL_MSG_TYPE_DAO_HANDLE,
RPL_MSG_TYPE_ROUTING_ENTRY_UPDATE,
RPL_MSG_TYPE_TRICKLE_INTERVAL,
RPL_MSG_TYPE_TRICKLE_CALLBACK
};
/* packet base lengths */ /* packet base lengths */
#define DIO_BASE_LEN 24 #define DIO_BASE_LEN 24
#define DIS_BASE_LEN 2 #define DIS_BASE_LEN 2
@ -147,6 +156,7 @@ static inline bool RPL_COUNTER_GREATER_THAN(uint8_t A, uint8_t B)
#define RPL_ROOT_RANK 256 #define RPL_ROOT_RANK 256
#define RPL_DEFAULT_LIFETIME 0xff #define RPL_DEFAULT_LIFETIME 0xff
#define RPL_LIFETIME_UNIT 2 #define RPL_LIFETIME_UNIT 2
#define RPL_LIFETIME_STEP 2
#define RPL_GROUNDED 1 #define RPL_GROUNDED 1
#define RPL_PRF_MASK 0x7 #define RPL_PRF_MASK 0x7
#define RPL_MOP_SHIFT 3 #define RPL_MOP_SHIFT 3

View File

@ -26,6 +26,8 @@
extern "C" { extern "C" {
#endif #endif
void rpl_dao_ack_received(rpl_dodag_t *dodag);
void rpl_delay_dao(rpl_dodag_t *dodag);
void rpl_instances_init(void); void rpl_instances_init(void);
rpl_instance_t *rpl_new_instance(uint8_t instanceid); rpl_instance_t *rpl_new_instance(uint8_t instanceid);
rpl_instance_t *rpl_get_instance(uint8_t instanceid); rpl_instance_t *rpl_get_instance(uint8_t instanceid);

View File

@ -18,9 +18,6 @@
* @} * @}
*/ */
#include <string.h>
#include "ipv6.h"
#ifndef RPL_STRUCTS_H_INCLUDED #ifndef RPL_STRUCTS_H_INCLUDED
#define RPL_STRUCTS_H_INCLUDED #define RPL_STRUCTS_H_INCLUDED
@ -28,6 +25,10 @@
extern "C" { extern "C" {
#endif #endif
#include <string.h>
#include "ipv6.h"
#include "trickle.h"
/* Modes of Operation */ /* Modes of Operation */
/* DIO Base Object (RFC 6550 Fig. 14) */ /* DIO Base Object (RFC 6550 Fig. 14) */
@ -167,6 +168,11 @@ typedef struct rpl_dodag_t {
uint8_t joined; uint8_t joined;
rpl_parent_t *my_preferred_parent; rpl_parent_t *my_preferred_parent;
struct rpl_of_t *of; struct rpl_of_t *of;
trickle_t trickle;
bool ack_received;
uint8_t dao_counter;
timex_t dao_time;
vtimer_t dao_timer;
} rpl_dodag_t; } rpl_dodag_t;
typedef struct rpl_of_t { typedef struct rpl_of_t {

View File

@ -282,6 +282,7 @@ int icmpv6_demultiplex(const icmpv6_hdr_t *hdr)
if (_rpl_process_pid != KERNEL_PID_UNDEF) { if (_rpl_process_pid != KERNEL_PID_UNDEF) {
msg_t m_send; msg_t m_send;
m_send.content.ptr = (char *) ipv6_buf; m_send.content.ptr = (char *) ipv6_buf;
m_send.type = ((icmpv6_hdr_t *)(m_send.content.ptr + IPV6_HDR_LEN))->code;
msg_send(&m_send, _rpl_process_pid); msg_send(&m_send, _rpl_process_pid);
} }
else { else {

View File

@ -45,8 +45,6 @@
#define ENABLE_DEBUG (0) #define ENABLE_DEBUG (0)
#if ENABLE_DEBUG #if ENABLE_DEBUG
#undef TRICKLE_TIMER_STACKSIZE
#define TRICKLE_TIMER_STACKSIZE (KERNEL_CONF_STACKSIZE_MAIN)
char addr_str[IPV6_MAX_ADDR_STR_LEN]; char addr_str[IPV6_MAX_ADDR_STR_LEN];
#endif #endif
#include "debug.h" #include "debug.h"
@ -57,6 +55,11 @@ mutex_t rpl_send_mutex = MUTEX_INIT;
msg_t rpl_msg_queue[RPL_PKT_RECV_BUF_SIZE]; msg_t rpl_msg_queue[RPL_PKT_RECV_BUF_SIZE];
char rpl_process_buf[RPL_PROCESS_STACKSIZE]; char rpl_process_buf[RPL_PROCESS_STACKSIZE];
uint8_t rpl_buffer[BUFFER_SIZE - LL_HDR_LEN]; uint8_t rpl_buffer[BUFFER_SIZE - LL_HDR_LEN];
static timex_t rt_time;
static vtimer_t rt_timer;
static void _dao_handle_send(rpl_dodag_t *dodag);
static void _rpl_update_routing_table(void);
#if RPL_DEFAULT_MOP == RPL_NON_STORING_MODE #if RPL_DEFAULT_MOP == RPL_NON_STORING_MODE
uint8_t srh_buffer[BUFFER_SIZE]; uint8_t srh_buffer[BUFFER_SIZE];
@ -74,7 +77,6 @@ ipv6_addr_t my_address;
/* IPv6 message buffer */ /* IPv6 message buffer */
ipv6_hdr_t *ipv6_buf; ipv6_hdr_t *ipv6_buf;
icmpv6_hdr_t *icmp_buf;
uint8_t rpl_init(int if_id) uint8_t rpl_init(int if_id)
{ {
@ -86,7 +88,6 @@ uint8_t rpl_init(int if_id)
rpl_clear_routing_table(); rpl_clear_routing_table();
#endif #endif
init_trickle();
rpl_process_pid = thread_create(rpl_process_buf, RPL_PROCESS_STACKSIZE, rpl_process_pid = thread_create(rpl_process_buf, RPL_PROCESS_STACKSIZE,
PRIORITY_MAIN - 1, CREATE_STACKTEST, PRIORITY_MAIN - 1, CREATE_STACKTEST,
rpl_process, NULL, "rpl_process"); rpl_process, NULL, "rpl_process");
@ -106,6 +107,10 @@ uint8_t rpl_init(int if_id)
/* initialize objective function manager */ /* initialize objective function manager */
rpl_of_manager_init(&my_address); rpl_of_manager_init(&my_address);
rpl_init_mode(&my_address); rpl_init_mode(&my_address);
rt_time = timex_set(RPL_LIFETIME_STEP, 0);
vtimer_set_msg(&rt_timer, rt_time, rpl_process_pid, RPL_MSG_TYPE_ROUTING_ENTRY_UPDATE, NULL);
return SIXLOWERROR_SUCCESS; return SIXLOWERROR_SUCCESS;
} }
@ -133,7 +138,9 @@ uint8_t rpl_is_root(void)
#if RPL_DEFAULT_MOP == RPL_NON_STORING_MODE #if RPL_DEFAULT_MOP == RPL_NON_STORING_MODE
void internal_srh_process(ipv6_srh_t *srh_header) void internal_srh_process(ipv6_srh_t *srh_header)
{ {
/* modify it accordingly - the number of entries is not depending on padding, because there is none. */ /* modify it accordingly - the number of entries is not depending on padding,
* because there is none.
*/
uint8_t n = srh_header->hdrextlen / sizeof(ipv6_addr_t); uint8_t n = srh_header->hdrextlen / sizeof(ipv6_addr_t);
if (srh_header->segments_left > n) { if (srh_header->segments_left > n) {
@ -146,7 +153,8 @@ void internal_srh_process(ipv6_srh_t *srh_header)
down_next_hop = &srh_header->route[n - segs]; down_next_hop = &srh_header->route[n - segs];
srh_header->segments_left = segs - 1; srh_header->segments_left = segs - 1;
DEBUGF("Segments left after reduction: %d\n", srh_header->segments_left); DEBUGF("Segments left after reduction: %d\n", srh_header->segments_left);
DEBUGF("Next hop is: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, down_next_hop)); DEBUGF("Next hop is: %s\n",
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, down_next_hop));
} }
} }
#endif #endif
@ -158,81 +166,122 @@ void *rpl_process(void *arg)
msg_t m_recv; msg_t m_recv;
msg_init_queue(rpl_msg_queue, RPL_PKT_RECV_BUF_SIZE); msg_init_queue(rpl_msg_queue, RPL_PKT_RECV_BUF_SIZE);
rpl_dodag_t *dodag;
trickle_t *trickle;
while (1) { while (1) {
msg_receive(&m_recv); msg_receive(&m_recv);
/* differentiate packet types */ if (m_recv.type > ICMP_CODE_END) {
ipv6_buf = ((ipv6_hdr_t *)m_recv.content.ptr); switch (m_recv.type) {
memcpy(&rpl_buffer, ipv6_buf, NTOHS(ipv6_buf->length) + IPV6_HDR_LEN); case RPL_MSG_TYPE_DAO_HANDLE:
dodag = (rpl_dodag_t *) m_recv.content.ptr;
/* This is an RPL-related message. */ if (dodag->joined) {
if (ipv6_buf->nextheader == IPV6_PROTO_NUM_ICMPV6) { _dao_handle_send(dodag);
icmp_buf = ((icmpv6_hdr_t *)(m_recv.content.ptr + IPV6_HDR_LEN)); }
/* get code for message-interpretation and process message */
DEBUGF("Received RPL information of type %04X and length %u\n", icmp_buf->code, NTOHS(ipv6_buf->length));
switch (icmp_buf->code) {
case (ICMP_CODE_DIS): {
rpl_recv_DIS();
break; break;
}
case (ICMP_CODE_DIO): { case RPL_MSG_TYPE_ROUTING_ENTRY_UPDATE:
rpl_recv_DIO(); _rpl_update_routing_table();
break; break;
}
case (ICMP_CODE_DAO): { case RPL_MSG_TYPE_TRICKLE_INTERVAL:
rpl_recv_DAO(); trickle = (trickle_t *) m_recv.content.ptr;
if (trickle->callback.func != NULL) {
trickle_interval(trickle);
}
break; break;
}
case (ICMP_CODE_DAO_ACK): { case RPL_MSG_TYPE_TRICKLE_CALLBACK:
rpl_recv_DAO_ACK(); trickle = (trickle_t *) m_recv.content.ptr;
if (trickle->callback.func != NULL) {
trickle_callback(trickle);
}
break; break;
}
default: default:
break; break;
} }
} }
/* This is an RPL-related message. */
else {
/* differentiate packet types */
ipv6_buf = (ipv6_hdr_t *) m_recv.content.ptr;
memcpy(&rpl_buffer, ipv6_buf, NTOHS(ipv6_buf->length) + IPV6_HDR_LEN);
if (ipv6_buf->nextheader == IPV6_PROTO_NUM_ICMPV6) {
/* get code for message-interpretation and process message */
DEBUGF("Received RPL information of type %04X and length %u\n",
m_recv.type, NTOHS(ipv6_buf->length));
switch (m_recv.type) {
case (ICMP_CODE_DIS): {
rpl_recv_DIS();
break;
}
case (ICMP_CODE_DIO): {
rpl_recv_DIO();
break;
}
case (ICMP_CODE_DAO): {
rpl_recv_DAO();
break;
}
case (ICMP_CODE_DAO_ACK): {
rpl_recv_DAO_ACK();
break;
}
default:
break;
}
}
#if RPL_DEFAULT_MOP == RPL_NON_STORING_MODE #if RPL_DEFAULT_MOP == RPL_NON_STORING_MODE
/* If the message is not RPL-type, it relates to non-storing mode */ /* If the message is not RPL-type, it relates to non-storing mode */
else if (RPL_DEFAULT_MOP == RPL_NON_STORING_MODE) { else if (RPL_DEFAULT_MOP == RPL_NON_STORING_MODE) {
if (ipv6_buf->nextheader == IPV6_PROTO_NUM_SRH) { if (ipv6_buf->nextheader == IPV6_PROTO_NUM_SRH) {
srh_header = ((ipv6_srh_t *)(m_recv.content.ptr + IPV6_HDR_LEN)); srh_header = ((ipv6_srh_t *)(m_recv.content.ptr + IPV6_HDR_LEN));
/* if there are no segments left, the routing is finished */ /* if there are no segments left, the routing is finished */
if (srh_header->segments_left == 0) { if (srh_header->segments_left == 0) {
DEBUGF("Source routing finished with next header: %02X.\n", srh_header->nextheader); DEBUGF("Source routing finished with next header: %02X.\n",
DEBUGF("Size of srh: %d\n", srh_header->hdrextlen); srh_header->nextheader);
uint8_t *payload = ((uint8_t *)(m_recv.content.ptr + IPV6_HDR_LEN + sizeof(ipv6_srh_t)+srh_header->hdrextlen)); DEBUGF("Size of srh: %d\n", srh_header->hdrextlen);
rpl_remove_srh_header(ipv6_buf, payload, srh_header->nextheader); uint8_t *payload = ((uint8_t *)(m_recv.content.ptr +
} IPV6_HDR_LEN + sizeof(ipv6_srh_t)+srh_header->hdrextlen));
else { rpl_remove_srh_header(ipv6_buf, payload, srh_header->nextheader);
internal_srh_process(srh_header); }
if (down_next_hop != NULL) { else {
uint8_t *payload = ((uint8_t *)(m_recv.content.ptr + IPV6_HDR_LEN)); internal_srh_process(srh_header);
rpl_srh_sendto(payload, NTOHS(ipv6_buf->length), &ipv6_buf->srcaddr, down_next_hop, srh_header, 0); if (down_next_hop != NULL) {
uint8_t *payload = ((uint8_t *)(m_recv.content.ptr + IPV6_HDR_LEN));
rpl_srh_sendto(payload, NTOHS(ipv6_buf->length), &ipv6_buf->srcaddr,
down_next_hop, srh_header, 0);
}
} }
} }
}
#if RPL_MAX_ROUTING_ENTRIES != 0 #if RPL_MAX_ROUTING_ENTRIES != 0
else { else {
srh_header = rpl_get_srh_header(ipv6_buf); srh_header = rpl_get_srh_header(ipv6_buf);
if (srh_header != NULL) { if (srh_header != NULL) {
uint8_t *payload = ((uint8_t *)(m_recv.content.ptr + IPV6_HDR_LEN)); uint8_t *payload = ((uint8_t *)(m_recv.content.ptr + IPV6_HDR_LEN));
rpl_srh_sendto(payload, NTOHS(ipv6_buf->length), &ipv6_buf->srcaddr, &ipv6_buf->destaddr, srh_header, srh_header->hdrextlen + sizeof(ipv6_srh_t)); rpl_srh_sendto(payload, NTOHS(ipv6_buf->length),
&ipv6_buf->srcaddr, &ipv6_buf->destaddr, srh_header,
srh_header->hdrextlen + sizeof(ipv6_srh_t));
}
} }
#endif
} }
#endif #endif
} }
#endif
} }
} }
@ -247,7 +296,8 @@ void rpl_send_DIO(ipv6_addr_t *destination)
mutex_unlock(&rpl_send_mutex); mutex_unlock(&rpl_send_mutex);
} }
void rpl_send_DAO(ipv6_addr_t *destination, uint8_t lifetime, bool default_lifetime, uint8_t start_index) void rpl_send_DAO(ipv6_addr_t *destination, uint8_t lifetime,
bool default_lifetime, uint8_t start_index)
{ {
if (destination) { if (destination) {
DEBUGF("Send DAO to %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, destination)); DEBUGF("Send DAO to %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, destination));
@ -272,7 +322,8 @@ void rpl_send_DIS(ipv6_addr_t *destination)
void rpl_send_DAO_ACK(ipv6_addr_t *destination) void rpl_send_DAO_ACK(ipv6_addr_t *destination)
{ {
if (destination) { if (destination) {
DEBUGF("Send DAO ACK to %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, destination)); DEBUGF("Send DAO ACK to %s\n",
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, destination));
} }
mutex_lock(&rpl_send_mutex); mutex_lock(&rpl_send_mutex);
@ -309,26 +360,109 @@ void rpl_recv_DAO_ACK(void)
rpl_recv_dao_ack_mode(); rpl_recv_dao_ack_mode();
} }
void _rpl_update_routing_table(void) {
rpl_dodag_t *my_dodag = rpl_get_my_dodag();
rpl_routing_entry_t *rt;
if (my_dodag != NULL) {
rt = rpl_get_routing_table();
for (uint8_t i = 0; i < rpl_max_routing_entries; i++) {
if (rt[i].used) {
if (rt[i].lifetime <= 1) {
memset(&rt[i], 0, sizeof(rt[i]));
}
else {
rt[i].lifetime = rt[i].lifetime - RPL_LIFETIME_STEP;
}
}
}
/* Parent is NULL for root too */
if (my_dodag->my_preferred_parent != NULL) {
if (my_dodag->my_preferred_parent->lifetime <= 1) {
DEBUGF("parent lifetime timeout\n");
rpl_parent_update(NULL);
}
else {
my_dodag->my_preferred_parent->lifetime =
my_dodag->my_preferred_parent->lifetime - RPL_LIFETIME_STEP;
}
}
}
vtimer_remove(&rt_timer);
vtimer_set_msg(&rt_timer, rt_time, rpl_process_pid, RPL_MSG_TYPE_ROUTING_ENTRY_UPDATE, NULL);
}
void rpl_delay_dao(rpl_dodag_t *dodag)
{
dodag->dao_time = timex_set(DEFAULT_DAO_DELAY, 0);
dodag->dao_counter = 0;
dodag->ack_received = false;
vtimer_remove(&dodag->dao_timer);
vtimer_set_msg(&dodag->dao_timer, dodag->dao_time,
rpl_process_pid, RPL_MSG_TYPE_DAO_HANDLE, dodag);
}
/* This function is used for regular update of the routes.
* The Timer can be overwritten, as the normal delay_dao function gets called
*/
void long_delay_dao(rpl_dodag_t *dodag)
{
dodag->dao_time = timex_set(REGULAR_DAO_INTERVAL, 0);
dodag->dao_counter = 0;
dodag->ack_received = false;
vtimer_remove(&dodag->dao_timer);
vtimer_set_msg(&dodag->dao_timer, dodag->dao_time,
rpl_process_pid, RPL_MSG_TYPE_DAO_HANDLE, dodag);
}
void rpl_dao_ack_received(rpl_dodag_t *dodag)
{
dodag->ack_received = true;
long_delay_dao(dodag);
}
void _dao_handle_send(rpl_dodag_t *dodag) {
if ((dodag->ack_received == false) && (dodag->dao_counter < DAO_SEND_RETRIES)) {
dodag->dao_counter++;
rpl_send_DAO(NULL, 0, true, 0);
dodag->dao_time = timex_set(DEFAULT_WAIT_FOR_DAO_ACK, 0);
vtimer_remove(&dodag->dao_timer);
vtimer_set_msg(&dodag->dao_timer, dodag->dao_time,
rpl_process_pid, RPL_MSG_TYPE_DAO_HANDLE, dodag);
}
else if (dodag->ack_received == false) {
long_delay_dao(dodag);
}
}
ipv6_addr_t *rpl_get_next_hop(ipv6_addr_t *addr) ipv6_addr_t *rpl_get_next_hop(ipv6_addr_t *addr)
{ {
DEBUGF("Looking up the next hop to %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, addr)); DEBUGF("Looking up the next hop to %s\n",
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, addr));
#if RPL_MAX_ROUTING_ENTRIES != 0 #if RPL_MAX_ROUTING_ENTRIES != 0
for (uint8_t i = 0; i < rpl_max_routing_entries; i++) { for (uint8_t i = 0; i < rpl_max_routing_entries; i++) {
if (rpl_routing_table[i].used) { if (rpl_routing_table[i].used) {
DEBUGF("checking %d: %s\n", i, ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &rpl_routing_table[i].address)); DEBUGF("checking %d: %s\n", i,
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &rpl_routing_table[i].address));
} }
if ((RPL_DEFAULT_MOP == RPL_NON_STORING_MODE) && rpl_is_root()) { if ((RPL_DEFAULT_MOP == RPL_NON_STORING_MODE) && rpl_is_root()) {
if (rpl_routing_table[i].used && rpl_equal_id(&rpl_routing_table[i].address, addr)) { if (rpl_routing_table[i].used && rpl_equal_id(&rpl_routing_table[i].address, addr)) {
DEBUGF("found %d: %s\n", i, ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &rpl_routing_table[i].address)); DEBUGF("found %d: %s\n", i,
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN,
&rpl_routing_table[i].address));
return &rpl_routing_table[i].address; return &rpl_routing_table[i].address;
} }
} }
else { else {
if (rpl_routing_table[i].used && rpl_equal_id(&rpl_routing_table[i].address, addr)) { if (rpl_routing_table[i].used && rpl_equal_id(&rpl_routing_table[i].address, addr)) {
DEBUGF("found %d: %s\n", i, ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &rpl_routing_table[i].next_hop)); DEBUGF("found %d: %s\n", i,
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN,
&rpl_routing_table[i].next_hop));
return &rpl_routing_table[i].next_hop; return &rpl_routing_table[i].next_hop;
} }
} }
@ -437,13 +571,16 @@ void rpl_add_srh_entry(ipv6_addr_t *child, ipv6_addr_t *parent, uint16_t lifetim
} }
} }
/* This maybe a bit confusing since the root also using the standard routing table, but in this case /* This maybe a bit confusing since the root also using the standard routing table,
* the code stays cleaner - especially for rt_over_timer from trickle.c. Just keep in mind that * but in this case the code stays cleaner - especially for rt_over_timer from trickle.c.
* address is now child (unique, iteration variable) and parent is now next_hop. The whole routing table * Just keep in mind that address is now child (unique, iteration variable) and parent is
* transforms to a list of children and their parents, so that route aggregation can be done properly. * now next_hop. The whole routing table transforms to a list of children and their parents,
* so that route aggregation can be done properly.
*/ */
DEBUGF("Adding source-routing entry child: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, child)); DEBUGF("Adding source-routing entry child: %s\n",
DEBUGF("Adding source-routing entry parent: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, parent)); ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, child));
DEBUGF("Adding source-routing entry parent: %s\n",
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, parent));
for (uint8_t i = 0; i < rpl_max_routing_entries; i++) { for (uint8_t i = 0; i < rpl_max_routing_entries; i++) {
if (!rpl_routing_table[i].used) { if (!rpl_routing_table[i].used) {
@ -486,13 +623,18 @@ ipv6_srh_t *rpl_get_srh_header(ipv6_hdr_t *act_ipv6_hdr)
DEBUGF("DESTINATION NODE: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, actual_node)); DEBUGF("DESTINATION NODE: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, actual_node));
while (!(rpl_equal_id(actual_node, &my_address))) { while (!(rpl_equal_id(actual_node, &my_address))) {
/* set check variable - this is reversed, if a child/parent-relation is found in one iteration of the routing table */ /* set check variable - this is reversed,
* if a child/parent-relation is found in one iteration of the routing table */
traceable = 0; traceable = 0;
for (uint8_t i = 0; i < rpl_max_routing_entries; i++) { for (uint8_t i = 0; i < rpl_max_routing_entries; i++) {
if (rpl_routing_table[i].used && ipv6_suffix_is_equal(&rpl_routing_table[i].address, actual_node)) { if (rpl_routing_table[i].used
DEBUGF("[INFO] Found parent-child relation with P: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &rpl_routing_table[i].next_hop)); && ipv6_suffix_is_equal(&rpl_routing_table[i].address, actual_node)) {
DEBUGF(" and C: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, actual_node)); DEBUGF("[INFO] Found parent-child relation with P: %s\n",
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN,
&rpl_routing_table[i].next_hop));
DEBUGF(" and C: %s\n",
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, actual_node));
memcpy(&rev_route[counter], actual_node, sizeof(ipv6_addr_t)); memcpy(&rev_route[counter], actual_node, sizeof(ipv6_addr_t));
actual_node = &rpl_routing_table[i].next_hop; actual_node = &rpl_routing_table[i].next_hop;
@ -514,7 +656,9 @@ ipv6_srh_t *rpl_get_srh_header(ipv6_hdr_t *act_ipv6_hdr)
} }
} }
/* build real route based on reversed route. After building it starts with the node next to destination */ /* build real route based on reversed route.
* After building it starts with the node next to destination
*/
if (counter > 1) { if (counter > 1) {
for (uint8_t i = 0; i < counter-1; i++) { for (uint8_t i = 0; i < counter-1; i++) {
memcpy(&srh_header->route[i], &rev_route[counter-i-2], sizeof(ipv6_addr_t)); memcpy(&srh_header->route[i], &rev_route[counter-i-2], sizeof(ipv6_addr_t));
@ -552,12 +696,14 @@ void rpl_remove_srh_header(ipv6_hdr_t *ipv6_header, const void *buf, uint8_t nex
temp_ipv6_header->nextheader = nextheader; temp_ipv6_header->nextheader = nextheader;
memcpy(payload, buf, msg_length); memcpy(payload, buf, msg_length);
DEBUGF("Source routing header extraction finished.\n"); DEBUGF("Source routing header extraction finished.\n");
DEBUGF("Dest is now: %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &temp_ipv6_header->destaddr)); DEBUGF("Dest is now: %s\n",
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &temp_ipv6_header->destaddr));
srh_m_send.content.ptr = (char *) srh_send_buffer; srh_m_send.content.ptr = (char *) srh_send_buffer;
msg_send_receive(&srh_m_send, &srh_m_recv, ip_process_pid); msg_send_receive(&srh_m_send, &srh_m_recv, ip_process_pid);
} }
int rpl_srh_sendto(const void *buf, uint16_t len, ipv6_addr_t *src, ipv6_addr_t *dest, ipv6_srh_t *srh_header, uint8_t srh_length) int rpl_srh_sendto(const void *buf, uint16_t len,
ipv6_addr_t *src, ipv6_addr_t *dest, ipv6_srh_t *srh_header, uint8_t srh_length)
{ {
ipv6_hdr_t *temp_ipv6_header = ((ipv6_hdr_t *)(&srh_send_buffer)); ipv6_hdr_t *temp_ipv6_header = ((ipv6_hdr_t *)(&srh_send_buffer));
ipv6_srh_t *current_packet = ((ipv6_srh_t *)(&srh_send_buffer[IPV6_HDR_LEN])); ipv6_srh_t *current_packet = ((ipv6_srh_t *)(&srh_send_buffer[IPV6_HDR_LEN]));
@ -572,6 +718,7 @@ int rpl_srh_sendto(const void *buf, uint16_t len, ipv6_addr_t *src, ipv6_addr_t
DEBUGF("SRH-length: %d\n", current_packet->hdrextlen); DEBUGF("SRH-length: %d\n", current_packet->hdrextlen);
DEBUGF("My payload length: %d\n", plength); DEBUGF("My payload length: %d\n", plength);
return ipv6_sendto(&temp_ipv6_header->destaddr, IPV6_PROTO_NUM_SRH, (uint8_t *)current_packet, plength, &temp_ipv6_header->destaddr); return ipv6_sendto(&temp_ipv6_header->destaddr, IPV6_PROTO_NUM_SRH,
(uint8_t *)current_packet, plength, &temp_ipv6_header->destaddr);
} }
#endif #endif

View File

@ -31,10 +31,19 @@ char addr_str[IPV6_MAX_ADDR_STR_LEN];
#endif #endif
#include "debug.h" #include "debug.h"
kernel_pid_t rpl_process_pid;
rpl_instance_t instances[RPL_MAX_INSTANCES]; rpl_instance_t instances[RPL_MAX_INSTANCES];
rpl_dodag_t dodags[RPL_MAX_DODAGS]; rpl_dodag_t dodags[RPL_MAX_DODAGS];
rpl_parent_t parents[RPL_MAX_PARENTS]; rpl_parent_t parents[RPL_MAX_PARENTS];
void rpl_trickle_send_dio(void *args) {
(void) args;
ipv6_addr_t mcast;
ipv6_addr_set_all_nodes_addr(&mcast);
rpl_send_DIO(&mcast);
}
void rpl_instances_init(void) void rpl_instances_init(void)
{ {
memset(instances, 0, sizeof(rpl_instance_t) * RPL_MAX_INSTANCES); memset(instances, 0, sizeof(rpl_instance_t) * RPL_MAX_INSTANCES);
@ -98,6 +107,9 @@ rpl_dodag_t *rpl_new_dodag(uint8_t instanceid, ipv6_addr_t *dodagid)
dodag->instance = inst; dodag->instance = inst;
dodag->my_rank = INFINITE_RANK; dodag->my_rank = INFINITE_RANK;
dodag->used = 1; dodag->used = 1;
dodag->ack_received = true;
dodag->dao_counter = 0;
dodag->trickle.callback.func = &rpl_trickle_send_dio;
memcpy(&dodag->dodag_id, dodagid, sizeof(*dodagid)); memcpy(&dodag->dodag_id, dodagid, sizeof(*dodagid));
return dodag; return dodag;
} }
@ -129,6 +141,7 @@ rpl_dodag_t *rpl_get_my_dodag(void)
} }
void rpl_del_dodag(rpl_dodag_t *dodag) void rpl_del_dodag(rpl_dodag_t *dodag)
{ {
rpl_leave_dodag(dodag);
memset(dodag, 0, sizeof(*dodag)); memset(dodag, 0, sizeof(*dodag));
} }
@ -137,6 +150,8 @@ void rpl_leave_dodag(rpl_dodag_t *dodag)
dodag->joined = 0; dodag->joined = 0;
dodag->my_preferred_parent = NULL; dodag->my_preferred_parent = NULL;
rpl_delete_all_parents(); rpl_delete_all_parents();
trickle_stop(&dodag->trickle);
vtimer_remove(&dodag->dao_timer);
} }
bool rpl_equal_id(ipv6_addr_t *id1, ipv6_addr_t *id2) bool rpl_equal_id(ipv6_addr_t *id1, ipv6_addr_t *id2)
@ -279,10 +294,10 @@ rpl_parent_t *rpl_find_preferred_parent(void)
my_dodag->my_preferred_parent = best; my_dodag->my_preferred_parent = best;
if (my_dodag->mop != RPL_NO_DOWNWARD_ROUTES) { if (my_dodag->mop != RPL_NO_DOWNWARD_ROUTES) {
delay_dao(); rpl_delay_dao(my_dodag);
} }
reset_trickletimer(); trickle_reset_timer(&my_dodag->trickle);
} }
return best; return best;
@ -315,7 +330,7 @@ void rpl_parent_update(rpl_parent_t *parent)
my_dodag->min_rank = my_dodag->my_rank; my_dodag->min_rank = my_dodag->my_rank;
} }
reset_trickletimer(); trickle_reset_timer(&my_dodag->trickle);
} }
} }
@ -367,8 +382,10 @@ void rpl_join_dodag(rpl_dodag_t *dodag, ipv6_addr_t *parent, uint16_t parent_ran
DEBUG("\tmy_preferred_parent rank\t%02X\n", my_dodag->my_preferred_parent->rank); DEBUG("\tmy_preferred_parent rank\t%02X\n", my_dodag->my_preferred_parent->rank);
DEBUG("\tmy_preferred_parent lifetime\t%04X\n", my_dodag->my_preferred_parent->lifetime); DEBUG("\tmy_preferred_parent lifetime\t%04X\n", my_dodag->my_preferred_parent->lifetime);
start_trickle(my_dodag->dio_min, my_dodag->dio_interval_doubling, my_dodag->dio_redundancy); trickle_start(rpl_process_pid, &my_dodag->trickle, RPL_MSG_TYPE_TRICKLE_INTERVAL,
delay_dao(); RPL_MSG_TYPE_TRICKLE_CALLBACK, (1 << my_dodag->dio_min), my_dodag->dio_interval_doubling,
my_dodag->dio_redundancy);
rpl_delay_dao(my_dodag);
} }
void rpl_global_repair(rpl_dodag_t *dodag, ipv6_addr_t *p_addr, uint16_t rank) void rpl_global_repair(rpl_dodag_t *dodag, ipv6_addr_t *p_addr, uint16_t rank)
@ -395,8 +412,8 @@ void rpl_global_repair(rpl_dodag_t *dodag, ipv6_addr_t *p_addr, uint16_t rank)
my_dodag->my_rank = my_dodag->of->calc_rank(my_dodag->my_preferred_parent, my_dodag->my_rank = my_dodag->of->calc_rank(my_dodag->my_preferred_parent,
my_dodag->my_rank); my_dodag->my_rank);
my_dodag->min_rank = my_dodag->my_rank; my_dodag->min_rank = my_dodag->my_rank;
reset_trickletimer(); trickle_reset_timer(&my_dodag->trickle);
delay_dao(); rpl_delay_dao(my_dodag);
} }
DEBUGF("Migrated to DODAG Version %d. My new Rank: %d\n", my_dodag->version, DEBUGF("Migrated to DODAG Version %d. My new Rank: %d\n", my_dodag->version,
@ -416,7 +433,7 @@ void rpl_local_repair(void)
my_dodag->my_rank = INFINITE_RANK; my_dodag->my_rank = INFINITE_RANK;
my_dodag->dtsn++; my_dodag->dtsn++;
rpl_delete_all_parents(); rpl_delete_all_parents();
reset_trickletimer(); trickle_reset_timer(&my_dodag->trickle);
} }

View File

@ -213,8 +213,10 @@ void rpl_init_root_mode(void)
return; return;
} }
trickle_start(rpl_process_pid, &dodag->trickle, RPL_MSG_TYPE_TRICKLE_INTERVAL,
RPL_MSG_TYPE_TRICKLE_CALLBACK, (1 << dodag->dio_min), dodag->dio_interval_doubling,
dodag->dio_redundancy);
DEBUGF("Root init finished.\n"); DEBUGF("Root init finished.\n");
start_trickle(dodag->dio_min, dodag->dio_interval_doubling, dodag->dio_redundancy);
} }
uint8_t rpl_is_root_mode(void) uint8_t rpl_is_root_mode(void)
@ -548,7 +550,7 @@ void rpl_recv_DIO_mode(void)
if (my_dodag->my_rank == ROOT_RANK) { if (my_dodag->my_rank == ROOT_RANK) {
DEBUGF("[Warning] Inconsistent Dodag Version\n"); DEBUGF("[Warning] Inconsistent Dodag Version\n");
my_dodag->version = RPL_COUNTER_INCREMENT(dio_dodag.version); my_dodag->version = RPL_COUNTER_INCREMENT(dio_dodag.version);
reset_trickletimer(); trickle_reset_timer(&my_dodag->trickle);
} }
else { else {
DEBUGF("my dodag has no preferred_parent yet - seems to be odd since I have a parent.\n"); DEBUGF("my dodag has no preferred_parent yet - seems to be odd since I have a parent.\n");
@ -558,20 +560,20 @@ void rpl_recv_DIO_mode(void)
return; return;
} }
else if (RPL_COUNTER_GREATER_THAN(my_dodag->version, dio_dodag.version)) { else if (RPL_COUNTER_GREATER_THAN(my_dodag->version, dio_dodag.version)) {
reset_trickletimer(); trickle_reset_timer(&my_dodag->trickle);
return; return;
} }
} }
/* version matches, DODAG matches */ /* version matches, DODAG matches */
if (rpl_dio_buf->rank == INFINITE_RANK) { if (rpl_dio_buf->rank == INFINITE_RANK) {
reset_trickletimer(); trickle_reset_timer(&my_dodag->trickle);
} }
/* We are root, all done!*/ /* We are root, all done!*/
if (my_dodag->my_rank == ROOT_RANK) { if (my_dodag->my_rank == ROOT_RANK) {
if (rpl_dio_buf->rank != INFINITE_RANK) { if (rpl_dio_buf->rank != INFINITE_RANK) {
trickle_increment_counter(); trickle_increment_counter(&my_dodag->trickle);
} }
return; return;
@ -592,7 +594,7 @@ void rpl_recv_DIO_mode(void)
} }
else { else {
/* DIO OK */ /* DIO OK */
trickle_increment_counter(); trickle_increment_counter(&my_dodag->trickle);
} }
/* update parent rank */ /* update parent rank */
@ -604,7 +606,7 @@ void rpl_recv_DIO_mode(void)
} }
else if (rpl_equal_id(&parent->addr, &my_dodag->my_preferred_parent->addr) && else if (rpl_equal_id(&parent->addr, &my_dodag->my_preferred_parent->addr) &&
(parent->dtsn != rpl_dio_buf->dtsn)) { (parent->dtsn != rpl_dio_buf->dtsn)) {
delay_dao(); rpl_delay_dao(my_dodag);
} }
parent->dtsn = rpl_dio_buf->dtsn; parent->dtsn = rpl_dio_buf->dtsn;
@ -699,7 +701,7 @@ void rpl_recv_DAO_mode(void)
if (increment_seq) { if (increment_seq) {
RPL_COUNTER_INCREMENT(my_dodag->dao_seq); RPL_COUNTER_INCREMENT(my_dodag->dao_seq);
delay_dao(); rpl_delay_dao(my_dodag);
} }
} }
@ -788,7 +790,7 @@ void rpl_recv_dao_ack_mode(void)
return; return;
} }
dao_ack_received(); rpl_dao_ack_received(my_dodag);
} }

View File

@ -215,7 +215,9 @@ void rpl_init_root_mode(void)
} }
i_am_root = 1; i_am_root = 1;
start_trickle(dodag->dio_min, dodag->dio_interval_doubling, dodag->dio_redundancy); trickle_start(rpl_process_pid, &dodag->trickle, RPL_MSG_TYPE_TRICKLE_INTERVAL,
RPL_MSG_TYPE_TRICKLE_CALLBACK, (1 << dodag->dio_min), dodag->dio_interval_doubling,
dodag->dio_redundancy);
DEBUGF("ROOT INIT FINISHED\n"); DEBUGF("ROOT INIT FINISHED\n");
} }
@ -570,7 +572,7 @@ void rpl_recv_DIO_mode(void)
if (my_dodag->my_rank == ROOT_RANK) { if (my_dodag->my_rank == ROOT_RANK) {
DEBUGF("[Warning] Inconsistent Dodag Version\n"); DEBUGF("[Warning] Inconsistent Dodag Version\n");
my_dodag->version = RPL_COUNTER_INCREMENT(dio_dodag.version); my_dodag->version = RPL_COUNTER_INCREMENT(dio_dodag.version);
reset_trickletimer(); trickle_reset_timer(&my_dodag->trickle);
} }
else { else {
DEBUGF("my dodag has no preferred_parent yet - seems to be odd since I have a parent.\n"); DEBUGF("my dodag has no preferred_parent yet - seems to be odd since I have a parent.\n");
@ -581,20 +583,20 @@ void rpl_recv_DIO_mode(void)
} }
else if (RPL_COUNTER_GREATER_THAN(my_dodag->version, dio_dodag.version)) { else if (RPL_COUNTER_GREATER_THAN(my_dodag->version, dio_dodag.version)) {
/* lower version number detected -> send more DIOs */ /* lower version number detected -> send more DIOs */
reset_trickletimer(); trickle_reset_timer(&my_dodag->trickle);
return; return;
} }
} }
/* version matches, DODAG matches */ /* version matches, DODAG matches */
if (rpl_dio_buf->rank == INFINITE_RANK) { if (rpl_dio_buf->rank == INFINITE_RANK) {
reset_trickletimer(); trickle_reset_timer(&my_dodag->trickle);
} }
/* We are root, all done!*/ /* We are root, all done!*/
if (my_dodag->my_rank == ROOT_RANK) { if (my_dodag->my_rank == ROOT_RANK) {
if (rpl_dio_buf->rank != INFINITE_RANK) { if (rpl_dio_buf->rank != INFINITE_RANK) {
trickle_increment_counter(); trickle_increment_counter(&my_dodag->trickle);
} }
return; return;
@ -615,7 +617,7 @@ void rpl_recv_DIO_mode(void)
} }
else { else {
/* DIO OK */ /* DIO OK */
trickle_increment_counter(); trickle_increment_counter(&my_dodag->trickle);
} }
/* update parent rank */ /* update parent rank */
@ -627,7 +629,7 @@ void rpl_recv_DIO_mode(void)
} }
else if (rpl_equal_id(&parent->addr, &my_dodag->my_preferred_parent->addr) && else if (rpl_equal_id(&parent->addr, &my_dodag->my_preferred_parent->addr) &&
(parent->dtsn != rpl_dio_buf->dtsn)) { (parent->dtsn != rpl_dio_buf->dtsn)) {
delay_dao(); rpl_delay_dao(my_dodag);
} }
parent->dtsn = rpl_dio_buf->dtsn; parent->dtsn = rpl_dio_buf->dtsn;
@ -722,7 +724,7 @@ void rpl_recv_DAO_mode(void)
if (increment_seq) { if (increment_seq) {
RPL_COUNTER_INCREMENT(my_dodag->dao_seq); RPL_COUNTER_INCREMENT(my_dodag->dao_seq);
delay_dao(); rpl_delay_dao(my_dodag);
} }
} }
@ -811,7 +813,7 @@ void rpl_recv_dao_ack_mode(void)
return; return;
} }
dao_ack_received(); rpl_dao_ack_received(my_dodag);
} }

View File

@ -1,288 +0,0 @@
/**
* Copyright (C) 2013 INRIA.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup rpl
* @{
* @file trickle.c
* @brief Trickle
*
* Implementation of Trickle-Algorithm for RPL.
*
* @author Eric Engel <eric.engel@fu-berlin.de>
* @}
*/
#include <string.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "inttypes.h"
#include "trickle.h"
#include "rpl.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
/* thread stacks */
static char timer_over_buf[TRICKLE_TIMER_STACKSIZE];
static char interval_over_buf[TRICKLE_INTERVAL_STACKSIZE];
static char dao_delay_over_buf[DAO_DELAY_STACKSIZE];
static char routing_table_buf[RT_STACKSIZE];
kernel_pid_t timer_over_pid = KERNEL_PID_UNDEF;
kernel_pid_t interval_over_pid = KERNEL_PID_UNDEF;
kernel_pid_t dao_delay_over_pid = KERNEL_PID_UNDEF;
kernel_pid_t rt_timer_over_pid = KERNEL_PID_UNDEF;
bool ack_received;
uint8_t dao_counter;
uint8_t k;
uint32_t Imin;
uint8_t Imax;
uint32_t I;
uint32_t t;
uint16_t c;
vtimer_t trickle_t_timer;
vtimer_t trickle_I_timer;
vtimer_t dao_timer;
vtimer_t rt_timer;
timex_t t_time;
timex_t I_time;
timex_t dao_time;
timex_t rt_time;
static void *trickle_timer_over(void *arg);
static void *trickle_interval_over(void *arg);
static void *dao_delay_over(void *arg);
static void *rt_timer_over(void *arg);
void reset_trickletimer(void)
{
I = Imin;
c = 0;
/* start timer */
t = (I / 2) + (rand() % (I - (I / 2) + 1));
t_time = timex_set(0, t * 1000);
I_time = timex_set(0, I * 1000);
timex_normalize(&t_time);
timex_normalize(&I_time);
vtimer_remove(&trickle_t_timer);
vtimer_remove(&trickle_I_timer);
vtimer_set_wakeup(&trickle_t_timer, t_time, timer_over_pid);
vtimer_set_wakeup(&trickle_I_timer, I_time, interval_over_pid);
}
void init_trickle(void)
{
/* Create threads */
ack_received = true;
dao_counter = 0;
timer_over_pid = thread_create(timer_over_buf, TRICKLE_TIMER_STACKSIZE,
PRIORITY_MAIN - 1, CREATE_STACKTEST,
trickle_timer_over, NULL, "trickle_timer_over");
interval_over_pid = thread_create(interval_over_buf, TRICKLE_INTERVAL_STACKSIZE,
PRIORITY_MAIN - 1, CREATE_STACKTEST,
trickle_interval_over, NULL, "trickle_interval_over");
dao_delay_over_pid = thread_create(dao_delay_over_buf, DAO_DELAY_STACKSIZE,
PRIORITY_MAIN - 1, CREATE_STACKTEST,
dao_delay_over, NULL, "dao_delay_over");
rt_timer_over_pid = thread_create(routing_table_buf, RT_STACKSIZE,
PRIORITY_MAIN - 1, CREATE_STACKTEST,
rt_timer_over, NULL, "rt_timer_over");
}
void start_trickle(uint8_t DIOIntMin, uint8_t DIOIntDoubl,
uint8_t DIORedundancyConstant)
{
c = 0;
k = DIORedundancyConstant;
Imin = (1 << DIOIntMin);
Imax = DIOIntDoubl;
/* Eigentlich laut Spezifikation erste Bestimmung von I wie auskommentiert: */
/* I = Imin + ( rand() % ( (Imin << Imax) - Imin + 1 ) ); */
I = Imin + (rand() % (4 * Imin)) ;
t = (I / 2) + (rand() % (I - (I / 2) + 1));
t_time = timex_set(0, t * 1000);
timex_normalize(&t_time);
I_time = timex_set(0, I * 1000);
timex_normalize(&I_time);
vtimer_remove(&trickle_t_timer);
vtimer_remove(&trickle_I_timer);
vtimer_set_wakeup(&trickle_t_timer, t_time, timer_over_pid);
vtimer_set_wakeup(&trickle_I_timer, I_time, interval_over_pid);
}
void trickle_increment_counter(void)
{
/* call this function, when received DIO message */
c++;
}
static void *trickle_timer_over(void *arg)
{
(void) arg;
ipv6_addr_t mcast;
ipv6_addr_set_all_nodes_addr(&mcast);
while (1) {
thread_sleep();
/* Handle k=0 like k=infinity (according to RFC6206, section 6.5) */
if ((c < k) || (k == 0)) {
rpl_send_DIO(&mcast);
}
}
return NULL;
}
static void *trickle_interval_over(void *arg)
{
(void) arg;
while (1) {
thread_sleep();
I = I * 2;
DEBUG("TRICKLE new Interval %" PRIu32 "\n", I);
if (I == 0) {
DEBUGF("[WARNING] Interval was 0\n");
if (Imax == 0) {
DEBUGF("[WARNING] Imax == 0\n");
}
I = (Imin << Imax);
}
if (I > (Imin << Imax)) {
I = (Imin << Imax);
}
c = 0;
t = (I / 2) + (rand() % (I - (I / 2) + 1));
/* start timer */
t_time = timex_set(0, t * 1000);
timex_normalize(&t_time);
I_time = timex_set(0, I * 1000);
timex_normalize(&I_time);
vtimer_remove(&trickle_t_timer);
if (vtimer_set_wakeup(&trickle_t_timer, t_time, timer_over_pid) != 0) {
DEBUGF("[ERROR] setting Wakeup\n");
}
vtimer_remove(&trickle_I_timer);
if (vtimer_set_wakeup(&trickle_I_timer, I_time, interval_over_pid) != 0) {
DEBUGF("[ERROR] setting Wakeup\n");
}
}
return NULL;
}
void delay_dao(void)
{
dao_time = timex_set(DEFAULT_DAO_DELAY, 0);
dao_counter = 0;
ack_received = false;
vtimer_remove(&dao_timer);
vtimer_set_wakeup(&dao_timer, dao_time, dao_delay_over_pid);
}
/* This function is used for regular update of the routes. The Timer can be overwritten, as the normal delay_dao function gets called */
void long_delay_dao(void)
{
dao_time = timex_set(REGULAR_DAO_INTERVAL, 0);
dao_counter = 0;
ack_received = false;
vtimer_remove(&dao_timer);
vtimer_set_wakeup(&dao_timer, dao_time, dao_delay_over_pid);
}
static void *dao_delay_over(void *arg)
{
(void) arg;
while (1) {
thread_sleep();
if ((ack_received == false) && (dao_counter < DAO_SEND_RETRIES)) {
dao_counter++;
rpl_send_DAO(NULL, 0, true, 0);
dao_time = timex_set(DEFAULT_WAIT_FOR_DAO_ACK, 0);
vtimer_remove(&dao_timer);
vtimer_set_wakeup(&dao_timer, dao_time, dao_delay_over_pid);
}
else if (ack_received == false) {
long_delay_dao();
}
}
return NULL;
}
void dao_ack_received(void)
{
ack_received = true;
long_delay_dao();
}
static void *rt_timer_over(void *arg)
{
(void) arg;
#if RPL_MAX_ROUTING_ENTRIES != 0
rpl_routing_entry_t *rt;
#endif
while (1) {
rpl_dodag_t *my_dodag = rpl_get_my_dodag();
if (my_dodag != NULL) {
#if RPL_MAX_ROUTING_ENTRIES != 0
rt = rpl_get_routing_table();
for (uint8_t i = 0; i < rpl_max_routing_entries; i++) {
if (rt[i].used) {
if (rt[i].lifetime <= 1) {
memset(&rt[i], 0, sizeof(rt[i]));
}
else {
rt[i].lifetime--;
}
}
}
#endif
/* Parent is NULL for root too */
if (my_dodag->my_preferred_parent != NULL) {
if (my_dodag->my_preferred_parent->lifetime <= 1) {
DEBUGF("parent lifetime timeout\n");
rpl_parent_update(NULL);
}
else {
my_dodag->my_preferred_parent->lifetime--;
}
}
}
/* Wake up every second */
vtimer_usleep(1000000);
}
return NULL;
}

View File

@ -1,42 +0,0 @@
/**
* Copyright (C) 2013 INRIA.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup rpl
* @{
* @file trickle.h
* @brief Trickle
*
* Header-file, which defines all Trickle constants and prototypes
*
* @author Eric Engel <eric.engel@fu-berlin.de>
* @}
*/
#include "vtimer.h"
#include "thread.h"
#ifdef __cplusplus
extern "C" {
#endif
#define TRICKLE_TIMER_STACKSIZE (KERNEL_CONF_STACKSIZE_MAIN)
#define TRICKLE_INTERVAL_STACKSIZE (KERNEL_CONF_STACKSIZE_MAIN)
#define DAO_DELAY_STACKSIZE (KERNEL_CONF_STACKSIZE_MAIN)
#define RT_STACKSIZE (KERNEL_CONF_STACKSIZE_DEFAULT)
void reset_trickletimer(void);
void init_trickle(void);
void start_trickle(uint8_t DIOINtMin, uint8_t DIOIntDoubl, uint8_t DIORedundancyConstatnt);
void trickle_increment_counter(void);
void delay_dao(void);
void dao_ack_received(void);
#ifdef __cplusplus
}
#endif

3
sys/trickle/Makefile Normal file
View File

@ -0,0 +1,3 @@
MODULE = trickle
include $(RIOTBASE)/Makefile.base

102
sys/trickle/trickle.c Normal file
View File

@ -0,0 +1,102 @@
/*
* Trickle implementation
*
* Copyright (C) 2013, 2014 INRIA.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @author Eric Engel <eric.engel@fu-berlin.de>
* @author Cenk Gündoğan <cnkgndgn@gmail.com>
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "inttypes.h"
#include "trickle.h"
#include "rpl.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
void trickle_callback(trickle_t *trickle)
{
/* Handle k=0 like k=infinity (according to RFC6206, section 6.5) */
if ((trickle->c < trickle->k) || (trickle->k == 0)) {
(*trickle->callback.func)(trickle->callback.args);
}
}
void trickle_interval(trickle_t *trickle)
{
trickle->I = trickle->I * 2;
DEBUG("TRICKLE new Interval %" PRIu32 "\n", trickle->I);
if (trickle->I == 0) {
DEBUGF("[WARNING] Interval was 0\n");
if (trickle->Imax == 0) {
DEBUGF("[WARNING] Imax == 0\n");
}
trickle->I = (trickle->Imin << trickle->Imax);
}
if (trickle->I > (trickle->Imin << trickle->Imax)) {
trickle->I = (trickle->Imin << trickle->Imax);
}
trickle->c = 0;
trickle->t = (trickle->I / 2) + (rand() % ((trickle->I / 2) + 1));
vtimer_remove(&trickle->msg_callback_timer);
trickle->msg_callback_time = timex_set(0, trickle->t * 1000);
vtimer_set_msg(&trickle->msg_callback_timer, trickle->msg_callback_time, trickle->pid,
trickle->callback_msg_type, trickle);
vtimer_remove(&trickle->msg_interval_timer);
trickle->msg_interval_time = timex_set(0, trickle->I * 1000);
vtimer_set_msg(&trickle->msg_interval_timer, trickle->msg_interval_time, trickle->pid,
trickle->interval_msg_type, trickle);
}
void trickle_reset_timer(trickle_t *trickle)
{
vtimer_remove(&trickle->msg_interval_timer);
vtimer_remove(&trickle->msg_callback_timer);
trickle_start(trickle->pid, trickle, trickle->interval_msg_type, trickle->callback_msg_type,
trickle->Imin, trickle->Imax, trickle->k);
}
void trickle_start(kernel_pid_t pid, trickle_t *trickle, uint16_t interval_msg_type,
uint16_t callback_msg_type, uint32_t Imin, uint8_t Imax, uint8_t k)
{
trickle->pid = pid;
trickle->c = 0;
trickle->k = k;
trickle->Imin = Imin;
trickle->Imax = Imax;
trickle->I = trickle->Imin + (rand() % (4 * trickle->Imin));
trickle->pid = pid;
trickle->interval_msg_type = interval_msg_type;
trickle->callback_msg_type = callback_msg_type;
trickle_interval(trickle);
}
void trickle_stop(trickle_t *trickle)
{
vtimer_remove(&trickle->msg_interval_timer);
vtimer_remove(&trickle->msg_callback_timer);
}
void trickle_increment_counter(trickle_t *trickle)
{
trickle->c++;
}