Added Orchestra, an autonomous scheduler for TSCH exploiting the local RPL state to maintain slotframes and links

This commit is contained in:
Simon Duquennoy 2015-09-21 18:52:26 +02:00
parent 20c97367a9
commit bc1e27cab7
8 changed files with 793 additions and 0 deletions

View file

@ -0,0 +1 @@
orchestra_src = orchestra.c orchestra-rule-default-common.c orchestra-rule-eb-per-time-source.c orchestra-rule-unicast-per-neighbor.c

51
apps/orchestra/README.md Normal file
View file

@ -0,0 +1,51 @@
# Orchestra
## Overview
Orchestra is an autonomous scheduling solution for TSCH, where nodes maintain
their own schedule solely based on their local RPL state. There is no centralized
scheduler nor negociatoin with neighbors, i.e. no traffic overhead. The default
Orchestra rules can be used out-of-box in any RPL network, reducing contention
to a low level. Orchestra is described and evaluated in
[*Orchestra: Robust Mesh Networks Through Autonomously Scheduled TSCH*](http://www.simonduquennoy.net/papers/duquennoy15orchestra.pdf), ACM SenSys'15.
## Requirements
Orchestra requires a system running TSCH and RPL.
For sender-based unicast slots (`ORCHESTRA_UNICAST_SENDER_BASED`), it requires
RPL with downwards routing enabled (relies on DAO).
## Getting Started
To use Orchestra, add a couple global definitions, e.g in your `project-conf.h` file.
Disable 6TiSCH minimal schedule:
`#define TSCH_SCHEDULE_CONF_WITH_6TISCH_MINIMAL 0`
Enable TSCH link selector (allows Orchestra to assign TSCH links to outgoing packets):
`#define TSCH_CONF_WITH_LINK_SELECTOR 1`
Set up the following callbacks:
```
#define TSCH_CALLBACK_NEW_TIME_SOURCE orchestra_callback_new_time_source
#define TSCH_CALLBACK_PACKET_READY orchestra_callback_packet_ready
#define NETSTACK_CONF_ROUTING_NEIGHBOR_ADDED_CALLBACK orchestra_callback_child_added
#define NETSTACK_CONF_ROUTING_NEIGHBOR_REMOVED_CALLBACK orchestra_callback_child_removed
```
To use Orchestra, fist add it to your makefile `APPS` with `APPS += orchestra`.
Finally:
* add Orchestra to your makefile `APPS` with `APPS += orchestra`;
* start Orchestra by calling `orchestra_init()` from your application, after
including `#include "orchestra.h"`.
## Configuration
Orchestra comes with a number of pre-installed rules, `orchestra-rule-*.c`.
You can define your own by using any of these as a template.
A default Orchestra configuration is described in `orchestra-conf.h`, define your own
`ORCHESTRA_CONF_*` macros to override modify the rule set and change rules configuration.

View file

@ -0,0 +1,105 @@
/*
* Copyright (c) 2015, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/**
* \file
* Orchestra configuration
*
* \author Simon Duquennoy <simonduq@sics.se>
*/
#ifndef __ORCHESTRA_CONF_H__
#define __ORCHESTRA_CONF_H__
#ifdef ORCHESTRA_CONF_RULES
#define ORCHESTRA_RULES ORCHESTRA_CONF_RULES
#else /* ORCHESTRA_CONF_RULES */
/* A default configuration with:
* - a sender-based slotframe for EB transmission
* - a sender-based or receiver-based slotframe for unicast to RPL parents and children
* - a common shared slotframe for any other traffic (mostly broadcast)
* */
#define ORCHESTRA_RULES { &eb_per_time_source, \
&unicast_per_neighbor, \
&default_common, \
}
#endif /* ORCHESTRA_CONF_RULES */
/* Length of the various slotframes. Tune to balance network capacity,
* contention, energy, latency. */
#ifdef ORCHESTRA_CONF_EBSF_PERIOD
#define ORCHESTRA_EBSF_PERIOD ORCHESTRA_CONF_EBSF_PERIOD
#else /* ORCHESTRA_CONF_EBSF_PERIOD */
#define ORCHESTRA_EBSF_PERIOD 397
#endif /* ORCHESTRA_CONF_EBSF_PERIOD */
#ifdef ORCHESTRA_CONF_COMMON_SHARED_PERIOD
#define ORCHESTRA_COMMON_SHARED_PERIOD ORCHESTRA_CONF_COMMON_SHARED_PERIOD
#else /* ORCHESTRA_CONF_COMMON_SHARED_PERIOD */
#define ORCHESTRA_COMMON_SHARED_PERIOD 31
#endif /* ORCHESTRA_CONF_COMMON_SHARED_PERIOD */
#ifdef ORCHESTRA_CONF_EBSF_PERIOD
#define ORCHESTRA_UNICAST_PERIOD ORCHESTRA_CONF_EBSF_PERIOD
#else /* ORCHESTRA_CONF_COMMON_SHARED_PERIOD */
#define ORCHESTRA_UNICAST_PERIOD 17
#endif /* ORCHESTRA_CONF_COMMON_SHARED_PERIOD */
/* Is the per-neighbor unicast slotframe sender-based (if not, it is receiver-based).
* Note: sender-based works only with RPL storing mode as it relies on DAO and
* routing entries to keep track of children and parents. */
#ifdef ORCHESTRA_CONF_UNICAST_SENDER_BASED
#define ORCHESTRA_UNICAST_SENDER_BASED ORCHESTRA_CONF_UNICAST_SENDER_BASED
#else /* ORCHESTRA_CONF_UNICAST_SENDER_BASED */
#define ORCHESTRA_UNICAST_SENDER_BASED 0
#endif /* ORCHESTRA_CONF_UNICAST_SENDER_BASED */
/* The hash function used to assign timeslot to a diven node (based on its link-layer address) */
#ifdef ORCHESTRA_CONF_LINKADDR_HASH
#define ORCHESTRA_LINKADDR_HASH ORCHESTRA_CONF_LINKADDR_HASH
#else /* ORCHESTRA_CONF_UNICAST_SENDER_BASED */
#define ORCHESTRA_LINKADDR_HASH(addr) ((addr != NULL) ? (addr)->u8[LINKADDR_SIZE - 1] : -1)
#endif /* ORCHESTRA_CONF_UNICAST_SENDER_BASED */
/* The maximum hash */
#ifdef ORCHESTRA_CONF_MAX_HASH
#define ORCHESTRA_MAX_HASH ORCHESTRA_CONF_MAX_HASH
#else /* ORCHESTRA_CONF_MAX_HASH */
#define ORCHESTRA_MAX_HASH 0x7fff
#endif /* ORCHESTRA_CONF_MAX_HASH */
/* Is the "hash" function collision-free? (e.g. it maps to unique node-ids) */
#ifdef ORCHESTRA_CONF_COLLISION_FREE_HASH
#define ORCHESTRA_COLLISION_FREE_HASH ORCHESTRA_CONF_COLLISION_FREE_HASH
#else /* ORCHESTRA_CONF_MAX_HASH */
#define ORCHESTRA_CONF_COLLISION_FREE_HASH 0 /* Set to 1 if ORCHESTRA_LINKADDR_HASH returns unique hashes */
#endif /* ORCHESTRA_CONF_MAX_HASH */
#endif /* __ORCHESTRA_CONF_H__ */

View file

@ -0,0 +1,86 @@
/*
* Copyright (c) 2015, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/**
* \file
* Orchestra: a slotframe with a single shared link, common to all nodes
* in the network, used for unicast and broadcast.
*
* \author Simon Duquennoy <simonduq@sics.se>
*/
#include "contiki.h"
#include "orchestra.h"
static uint16_t slotframe_handle = 0;
static uint16_t channel_offset = 0;
#if ORCHESTRA_EBSF_PERIOD > 0
/* There is a slotframe for EBs, use this slotframe for non-EB traffic only */
#define ORCHESTRA_COMMON_SHARED_TYPE LINK_TYPE_NORMAL
#else
/* There is no slotframe for EBs, use this slotframe both EB and non-EB traffic */
#define ORCHESTRA_COMMON_SHARED_TYPE LINK_TYPE_ADVERTISING
#endif
/*---------------------------------------------------------------------------*/
static int
select_packet(uint16_t *slotframe, uint16_t *timeslot)
{
/* We are the default slotframe, select anything */
if(slotframe != NULL) {
*slotframe = slotframe_handle;
}
if(timeslot != NULL) {
*timeslot = 0;
}
return 1;
}
/*---------------------------------------------------------------------------*/
static void
init(uint16_t sf_handle)
{
slotframe_handle = sf_handle;
channel_offset = slotframe_handle;
/* Default slotframe: for broadcast or unicast to neighbors we
* do not have a link to */
struct tsch_slotframe *sf_common = tsch_schedule_add_slotframe(slotframe_handle, ORCHESTRA_COMMON_SHARED_PERIOD);
tsch_schedule_add_link(sf_common,
LINK_OPTION_RX | LINK_OPTION_TX | LINK_OPTION_SHARED,
ORCHESTRA_COMMON_SHARED_TYPE, &tsch_broadcast_address,
0, channel_offset);
}
/*---------------------------------------------------------------------------*/
struct orchestra_rule default_common = {
init,
NULL,
select_packet,
NULL,
NULL,
};

View file

@ -0,0 +1,116 @@
/*
* Copyright (c) 2015, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/**
* \file
* Orchestra: a slotframe dedicated to transmission of EBs.
* Nodes transmit at a timeslot defined as hash(MAC) % ORCHESTRA_EBSF_PERIOD
* Nodes listen at a timeslot defined as hash(time_source.MAC) % ORCHESTRA_EBSF_PERIOD
* \author Simon Duquennoy <simonduq@sics.se>
*/
#include "contiki.h"
#include "orchestra.h"
#include "net/packetbuf.h"
static uint16_t slotframe_handle = 0;
static uint16_t channel_offset = 0;
static struct tsch_slotframe *sf_eb;
/*---------------------------------------------------------------------------*/
static uint16_t
get_node_timeslot(const linkaddr_t *addr)
{
#if ORCHESTRA_EBSF_PERIOD > 0
return ORCHESTRA_LINKADDR_HASH(addr) % ORCHESTRA_EBSF_PERIOD;
#else
return 0xffff;
#endif
}
/*---------------------------------------------------------------------------*/
static int
select_packet(uint16_t *slotframe, uint16_t *timeslot)
{
/* Select EBs only */
if(packetbuf_attr(PACKETBUF_ATTR_FRAME_TYPE) == FRAME802154_BEACONFRAME) {
if(slotframe != NULL) {
*slotframe = slotframe_handle;
}
if(timeslot != NULL) {
*timeslot = get_node_timeslot(&linkaddr_node_addr);
}
return 1;
}
return 0;
}
/*---------------------------------------------------------------------------*/
static void
new_time_source(const struct tsch_neighbor *old, const struct tsch_neighbor *new)
{
uint16_t old_ts = get_node_timeslot(&old->addr);
uint16_t new_ts = get_node_timeslot(&new->addr);
if(new_ts == old_ts) {
return;
}
if(old_ts != 0xffff) {
/* Stop listening to the old time source's EBs */
tsch_schedule_remove_link_by_timeslot(sf_eb, old_ts);
}
if(new_ts != 0xffff) {
/* Listen to the time source's EBs */
tsch_schedule_add_link(sf_eb,
LINK_OPTION_RX,
LINK_TYPE_ADVERTISING_ONLY, NULL,
new_ts, 0);
}
}
/*---------------------------------------------------------------------------*/
static void
init(uint16_t sf_handle)
{
slotframe_handle = sf_handle;
channel_offset = sf_handle;
sf_eb = tsch_schedule_add_slotframe(slotframe_handle, ORCHESTRA_EBSF_PERIOD);
/* EB link: every neighbor uses its own to avoid contention */
tsch_schedule_add_link(sf_eb,
LINK_OPTION_TX,
LINK_TYPE_ADVERTISING_ONLY, &tsch_broadcast_address,
get_node_timeslot(&linkaddr_node_addr), 0);
}
/*---------------------------------------------------------------------------*/
struct orchestra_rule eb_per_time_source = {
init,
new_time_source,
select_packet,
NULL,
NULL,
};

View file

@ -0,0 +1,194 @@
/*
* Copyright (c) 2015, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/**
* \file
* Orchestra: a slotframe dedicated to unicast data transmission.
* If sender-based:
* Nodes listen at a timeslot defined as hash(MAC) % ORCHESTRA_SB_UNICAST_PERIOD
* Nodes transmit at: for each nbr in RPL children and RPL preferred parent,
* hash(nbr.MAC) % ORCHESTRA_SB_UNICAST_PERIOD
* If receiver-based: the opposite
*
* \author Simon Duquennoy <simonduq@sics.se>
*/
#include "contiki.h"
#include "orchestra.h"
#include "net/ipv6/uip-ds6-route.h"
#include "net/packetbuf.h"
#if ORCHESTRA_UNICAST_SENDER_BASED && ORCHESTRA_COLLISION_FREE_HASH
#define UNICAST_SLOT_SHARED_FLAG ((ORCHESTRA_UNICAST_PERIOD < ORCHESTRA_MAX_HASH) ? LINK_OPTION_SHARED : 0)
#else
#define UNICAST_SLOT_SHARED_FLAG LINK_OPTION_SHARED
#endif
static uint16_t slotframe_handle = 0;
static uint16_t channel_offset = 0;
static struct tsch_slotframe *sf_unicast;
/*---------------------------------------------------------------------------*/
static uint16_t
get_node_timeslot(const linkaddr_t *addr)
{
if(addr != NULL && ORCHESTRA_UNICAST_PERIOD > 0) {
return ORCHESTRA_LINKADDR_HASH(addr) % ORCHESTRA_UNICAST_PERIOD;
} else {
return 0xffff;
}
}
/*---------------------------------------------------------------------------*/
static int
neighbor_has_uc_link(const linkaddr_t *linkaddr)
{
if(linkaddr != NULL && !linkaddr_cmp(linkaddr, &linkaddr_null)) {
if((orchestra_parent_knows_us || !ORCHESTRA_UNICAST_SENDER_BASED)
&& linkaddr_cmp(&orchestra_parent_linkaddr, linkaddr)) {
return 1;
}
if(nbr_table_get_from_lladdr(nbr_routes, (linkaddr_t *)linkaddr) != NULL) {
return 1;
}
}
return 0;
}
/*---------------------------------------------------------------------------*/
static void
add_uc_link(const linkaddr_t *linkaddr)
{
if(linkaddr != NULL) {
uint16_t timeslot = get_node_timeslot(linkaddr);
tsch_schedule_add_link(sf_unicast,
ORCHESTRA_UNICAST_SENDER_BASED ? LINK_OPTION_RX : LINK_OPTION_TX | UNICAST_SLOT_SHARED_FLAG,
LINK_TYPE_NORMAL, &tsch_broadcast_address,
timeslot, channel_offset);
}
}
/*---------------------------------------------------------------------------*/
static void
remove_uc_link(const linkaddr_t *linkaddr)
{
uint16_t timeslot;
struct tsch_link *l;
if(linkaddr == NULL) {
return;
}
timeslot = get_node_timeslot(linkaddr);
l = tsch_schedule_get_link_by_timeslot(sf_unicast, timeslot);
if(l == NULL) {
return;
}
/* Does our current parent need this timeslot? */
if(timeslot == get_node_timeslot(&orchestra_parent_linkaddr)) {
/* Yes, this timeslot is being used, return */
return;
}
/* Does any other child need this timeslot?
* (lookup all route next hops) */
nbr_table_item_t *item = nbr_table_head(nbr_routes);
while(item != NULL) {
linkaddr_t *addr = nbr_table_get_lladdr(nbr_routes, item);
if(timeslot == get_node_timeslot(addr)) {
/* Yes, this timeslot is being used, return */
return;
}
item = nbr_table_next(nbr_routes, item);
}
tsch_schedule_remove_link(sf_unicast, l);
}
/*---------------------------------------------------------------------------*/
static void
child_added(const linkaddr_t *linkaddr)
{
add_uc_link(linkaddr);
}
/*---------------------------------------------------------------------------*/
static void
child_removed(const linkaddr_t *linkaddr)
{
remove_uc_link(linkaddr);
}
/*---------------------------------------------------------------------------*/
static int
select_packet(uint16_t *slotframe, uint16_t *timeslot)
{
/* Select data packets we have a unicast link to */
const linkaddr_t *dest = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
if(packetbuf_attr(PACKETBUF_ATTR_FRAME_TYPE) == FRAME802154_DATAFRAME
&& neighbor_has_uc_link(dest)) {
if(slotframe != NULL) {
*slotframe = slotframe_handle;
}
if(timeslot != NULL) {
*timeslot = ORCHESTRA_UNICAST_SENDER_BASED ? get_node_timeslot(&linkaddr_node_addr) : get_node_timeslot(dest);
}
return 1;
}
return 0;
}
/*---------------------------------------------------------------------------*/
static void
new_time_source(const struct tsch_neighbor *old, const struct tsch_neighbor *new)
{
if(new != old) {
const linkaddr_t *new_addr = new != NULL ? &new->addr : NULL;
if(new_addr != NULL) {
linkaddr_copy(&orchestra_parent_linkaddr, new_addr);
} else {
linkaddr_copy(&orchestra_parent_linkaddr, &linkaddr_null);
}
remove_uc_link(new_addr);
add_uc_link(new_addr);
}
}
/*---------------------------------------------------------------------------*/
static void
init(uint16_t sf_handle)
{
slotframe_handle = sf_handle;
channel_offset = sf_handle;
/* Slotframe for unicast transmissions */
sf_unicast = tsch_schedule_add_slotframe(slotframe_handle, ORCHESTRA_UNICAST_PERIOD);
uint16_t timeslot = get_node_timeslot(&linkaddr_node_addr);
tsch_schedule_add_link(sf_unicast,
ORCHESTRA_UNICAST_SENDER_BASED ? LINK_OPTION_TX | UNICAST_SLOT_SHARED_FLAG: LINK_OPTION_RX,
LINK_TYPE_NORMAL, &tsch_broadcast_address,
timeslot, channel_offset);
}
/*---------------------------------------------------------------------------*/
struct orchestra_rule unicast_per_neighbor = {
init,
new_time_source,
select_packet,
child_added,
child_removed,
};

166
apps/orchestra/orchestra.c Normal file
View file

@ -0,0 +1,166 @@
/*
* Copyright (c) 2015, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/**
* \file
* Orchestra: an autonomous scheduler for TSCH exploiting RPL state.
* See "Orchestra: Robust Mesh Networks Through Autonomously Scheduled TSCH", ACM SenSys'15
*
* \author Simon Duquennoy <simonduq@sics.se>
*/
#include "contiki.h"
#include "orchestra.h"
#include "net/packetbuf.h"
#include "net/ipv6/uip-icmp6.h"
#include "net/rpl/rpl-private.h"
#include "net/rime/rime.h" /* Needed for so-called rime-sniffer */
#define DEBUG DEBUG_PRINT
#include "net/ip/uip-debug.h"
/* A net-layer sniffer for packets sent and received */
static void orchestra_packet_received(void);
static void orchestra_packet_sent(int mac_status);
RIME_SNIFFER(orhcestra_sniffer, orchestra_packet_received, orchestra_packet_sent);
/* The current RPL preferred parent's link-layer address */
linkaddr_t orchestra_parent_linkaddr;
/* Set to one only after getting an ACK for a DAO sent to our preferred parent */
int orchestra_parent_knows_us = 0;
/* The set of Orchestra rules in use */
const struct orchestra_rule *all_rules[] = ORCHESTRA_RULES;
#define NUM_RULES (sizeof(all_rules) / sizeof(struct orchestra_rule *))
/*---------------------------------------------------------------------------*/
static void
orchestra_packet_received(void)
{
}
/*---------------------------------------------------------------------------*/
static void
orchestra_packet_sent(int mac_status)
{
/* Check if our parent just ACKed a DAO */
if(orchestra_parent_knows_us == 0
&& mac_status == MAC_TX_OK
&& packetbuf_attr(PACKETBUF_ATTR_NETWORK_ID) == UIP_PROTO_ICMP6
&& packetbuf_attr(PACKETBUF_ATTR_CHANNEL) == (ICMP6_RPL << 8 | RPL_CODE_DAO)) {
if(!linkaddr_cmp(&orchestra_parent_linkaddr, &linkaddr_null)
&& linkaddr_cmp(&orchestra_parent_linkaddr, packetbuf_addr(PACKETBUF_ADDR_RECEIVER))) {
orchestra_parent_knows_us = 1;
}
}
}
/*---------------------------------------------------------------------------*/
void
orchestra_callback_child_added(const linkaddr_t *addr)
{
/* Notify all Orchestra rules that a child was added */
int i;
for(i = 0; i < NUM_RULES; i++) {
if(all_rules[i]->child_added != NULL) {
all_rules[i]->child_added(addr);
}
}
}
/*---------------------------------------------------------------------------*/
void
orchestra_callback_child_removed(const linkaddr_t *addr)
{
/* Notify all Orchestra rules that a child was removed */
int i;
for(i = 0; i < NUM_RULES; i++) {
if(all_rules[i]->child_removed != NULL) {
all_rules[i]->child_removed(addr);
}
}
}
/*---------------------------------------------------------------------------*/
void
orchestra_callback_packet_ready(void)
{
int i;
/* By default, use any slotframe, any timeslot */
uint16_t slotframe = 9;
uint16_t timeslot = 0xffff;
/* Loop over all rules until finding one able to handle the packet */
for(i = 0; i < NUM_RULES; i++) {
if(all_rules[i]->select_packet != NULL) {
if(all_rules[i]->select_packet(&slotframe, &timeslot)) {
break;
}
}
}
#if TSCH_WITH_LINK_SELECTOR
packetbuf_set_attr(PACKETBUF_ATTR_TSCH_SLOTFRAME, slotframe);
packetbuf_set_attr(PACKETBUF_ATTR_TSCH_TIMESLOT, timeslot);
#endif
}
/*---------------------------------------------------------------------------*/
void
orchestra_callback_new_time_source(const struct tsch_neighbor *old, const struct tsch_neighbor *new)
{
/* Orchestra assumes that the time source is also the RPL parent.
* This is the case if the following is set:
* #define RPL_CALLBACK_PARENT_SWITCH tsch_rpl_callback_parent_switch
* */
int i;
if(new != old) {
orchestra_parent_knows_us = 0;
}
for(i = 0; i < NUM_RULES; i++) {
if(all_rules[i]->new_time_source != NULL) {
all_rules[i]->new_time_source(old, new);
}
}
}
/*---------------------------------------------------------------------------*/
void
orchestra_init(void)
{
int i;
/* Snoop on packet transmission to know if our parent knows about us
* (i.e. has ACKed at one of our DAOs since we decided to use it as a parent) */
rime_sniffer_add(&orhcestra_sniffer);
linkaddr_copy(&orchestra_parent_linkaddr, &linkaddr_null);
/* Initialize all Orchestra rules */
for(i = 0; i < NUM_RULES; i++) {
if(all_rules[i]->init != NULL) {
PRINTF("Orchestra: initializing rule %u\n", i);
all_rules[i]->init(i);
}
}
PRINTF("Orchestra: initialization done\n");
}

View file

@ -0,0 +1,74 @@
/*
* Copyright (c) 2015, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/**
* \file
* Orchestra header file
*
* \author Simon Duquennoy <simonduq@sics.se>
*/
#ifndef __ORCHESTRA_H__
#define __ORCHESTRA_H__
#include "net/mac/tsch/tsch.h"
#include "net/mac/tsch/tsch-conf.h"
#include "net/mac/tsch/tsch-schedule.h"
#include "orchestra-conf.h"
/* The structure of an Orchestra rule */
struct orchestra_rule {
void (* init)(uint16_t slotframe_handle);
void (* new_time_source)(const struct tsch_neighbor *old, const struct tsch_neighbor *new);
int (* select_packet)(uint16_t *slotframe, uint16_t *timeslot);
void (* child_added)(const linkaddr_t *addr);
void (* child_removed)(const linkaddr_t *addr);
};
struct orchestra_rule eb_per_time_source;
struct orchestra_rule unicast_per_neighbor;
struct orchestra_rule default_common;
extern linkaddr_t orchestra_parent_linkaddr;
extern int orchestra_parent_knows_us;
/* Call from application to start Orchestra */
void orchestra_init(void);
/* Callbacks requied for Orchestra to operate */
/* Set with #define TSCH_CALLBACK_PACKET_READY orchestra_callback_packet_ready */
void orchestra_callback_packet_ready(void);
/* Set with #define TSCH_CALLBACK_NEW_TIME_SOURCE orchestra_callback_new_time_source */
void orchestra_callback_new_time_source(const struct tsch_neighbor *old, const struct tsch_neighbor *new);
/* Set with #define NETSTACK_CONF_ROUTING_NEIGHBOR_ADDED_CALLBACK orchestra_callback_child_added */
void orchestra_callback_child_added(const linkaddr_t *addr);
/* Set with #define NETSTACK_CONF_ROUTING_NEIGHBOR_REMOVED_CALLBACK orchestra_callback_child_removed */
void orchestra_callback_child_removed(const linkaddr_t *addr);
#endif /* __ORCHESTRA_H__ */