From bc1e27cab71dfe9d86948c073b6a6ec1021f7f66 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Mon, 21 Sep 2015 18:52:26 +0200 Subject: [PATCH] Added Orchestra, an autonomous scheduler for TSCH exploiting the local RPL state to maintain slotframes and links --- apps/orchestra/Makefile.orchestra | 1 + apps/orchestra/README.md | 51 +++++ apps/orchestra/orchestra-conf.h | 105 ++++++++++ .../orchestra/orchestra-rule-default-common.c | 86 ++++++++ .../orchestra-rule-eb-per-time-source.c | 116 +++++++++++ .../orchestra-rule-unicast-per-neighbor.c | 194 ++++++++++++++++++ apps/orchestra/orchestra.c | 166 +++++++++++++++ apps/orchestra/orchestra.h | 74 +++++++ 8 files changed, 793 insertions(+) create mode 100644 apps/orchestra/Makefile.orchestra create mode 100644 apps/orchestra/README.md create mode 100644 apps/orchestra/orchestra-conf.h create mode 100644 apps/orchestra/orchestra-rule-default-common.c create mode 100644 apps/orchestra/orchestra-rule-eb-per-time-source.c create mode 100644 apps/orchestra/orchestra-rule-unicast-per-neighbor.c create mode 100644 apps/orchestra/orchestra.c create mode 100644 apps/orchestra/orchestra.h diff --git a/apps/orchestra/Makefile.orchestra b/apps/orchestra/Makefile.orchestra new file mode 100644 index 000000000..314fdac23 --- /dev/null +++ b/apps/orchestra/Makefile.orchestra @@ -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 diff --git a/apps/orchestra/README.md b/apps/orchestra/README.md new file mode 100644 index 000000000..3a15b2e71 --- /dev/null +++ b/apps/orchestra/README.md @@ -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. diff --git a/apps/orchestra/orchestra-conf.h b/apps/orchestra/orchestra-conf.h new file mode 100644 index 000000000..cef850b1d --- /dev/null +++ b/apps/orchestra/orchestra-conf.h @@ -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 + */ + +#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__ */ diff --git a/apps/orchestra/orchestra-rule-default-common.c b/apps/orchestra/orchestra-rule-default-common.c new file mode 100644 index 000000000..49ac3b496 --- /dev/null +++ b/apps/orchestra/orchestra-rule-default-common.c @@ -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 + */ + +#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, +}; diff --git a/apps/orchestra/orchestra-rule-eb-per-time-source.c b/apps/orchestra/orchestra-rule-eb-per-time-source.c new file mode 100644 index 000000000..0f774f531 --- /dev/null +++ b/apps/orchestra/orchestra-rule-eb-per-time-source.c @@ -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 + */ + +#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, +}; diff --git a/apps/orchestra/orchestra-rule-unicast-per-neighbor.c b/apps/orchestra/orchestra-rule-unicast-per-neighbor.c new file mode 100644 index 000000000..994a896ab --- /dev/null +++ b/apps/orchestra/orchestra-rule-unicast-per-neighbor.c @@ -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 + */ + +#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, +}; diff --git a/apps/orchestra/orchestra.c b/apps/orchestra/orchestra.c new file mode 100644 index 000000000..fdf579f33 --- /dev/null +++ b/apps/orchestra/orchestra.c @@ -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 + */ + +#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, ×lot)) { + 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"); +} diff --git a/apps/orchestra/orchestra.h b/apps/orchestra/orchestra.h new file mode 100644 index 000000000..a895335b5 --- /dev/null +++ b/apps/orchestra/orchestra.h @@ -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 + */ + +#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__ */