Moved ETX management from neighbor-info to rpl-of-etx. Avoids conversions between different fixed point representations, and simplifies neighbor management. Makes more clear how default-ETX and noack-ETX actually affect the rank. Removed neighbor-info and neighbor-attr.

This commit is contained in:
Simon Duquennoy 2013-07-29 21:50:33 +02:00
parent c50d10aa53
commit c3f62b24c8
15 changed files with 86 additions and 757 deletions

View file

@ -1,8 +1,6 @@
NET = \ NET = \
dhcpc.c \ dhcpc.c \
hc.c \ hc.c \
neighbor-attr.c \
neighbor-info.c \
neighbor-table.c \ neighbor-table.c \
netstack.c \ netstack.c \
packetbuf.c \ packetbuf.c \

View file

@ -1,250 +0,0 @@
/*
* Copyright (c) 2010, Vrije Universiteit Brussel
* 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.
*
*
* Author: Joris Borms <joris.borms@vub.ac.be>
*
*/
#include "contiki.h"
#include "lib/memb.h"
#include "lib/list.h"
#include <stddef.h>
#include <string.h>
#include "net/neighbor-attr.h"
#define DEBUG 0
#if DEBUG
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif
static uint16_t timeout = 0;
MEMB(neighbor_addr_mem, struct neighbor_addr, NEIGHBOR_ATTR_MAX_NEIGHBORS);
LIST(neighbor_addrs);
LIST(neighbor_attrs);
/*---------------------------------------------------------------------------*/
static struct neighbor_addr *
neighbor_addr_get(const rimeaddr_t *addr)
{
struct neighbor_addr *item;
/* check if addr is derived from table, inside memb */
if(memb_inmemb(&neighbor_addr_mem, (char *)addr)) {
return (struct neighbor_addr *)
(((char *)addr) - offsetof(struct neighbor_addr, addr));
}
item = list_head(neighbor_addrs);
while(item != NULL) {
if(rimeaddr_cmp(addr, &item->addr)) {
return item;
}
item = item->next;
}
return NULL;
}
/*---------------------------------------------------------------------------*/
struct neighbor_addr *
neighbor_attr_list_neighbors(void)
{
return list_head(neighbor_addrs);
}
/*---------------------------------------------------------------------------*/
static void
set_attr(struct neighbor_attr *attr, uint16_t index)
{
if(attr->default_value != NULL) {
memcpy((char *)attr->data + index * attr->size,
attr->default_value, attr->size);
} else {
/* fill with zeroes */
memset((char *)attr->data + index * attr->size, 0, attr->size);
}
}
/*---------------------------------------------------------------------------*/
int
neighbor_attr_register(struct neighbor_attr *def)
{
struct neighbor_addr *addr;
list_push(neighbor_attrs, def);
/* set default values for already existing neighbors */
for(addr = list_head(neighbor_addrs); addr != NULL; addr = addr->next) {
set_attr(def, addr->index);
}
return 1;
}
/*---------------------------------------------------------------------------*/
int
neighbor_attr_has_neighbor(const rimeaddr_t *addr)
{
return neighbor_addr_get(addr) != NULL;
}
/*---------------------------------------------------------------------------*/
int
neighbor_attr_add_neighbor(const rimeaddr_t *addr)
{
struct neighbor_attr *def;
struct neighbor_addr *item;
struct neighbor_addr *ptr;
uint16_t i;
if(neighbor_attr_has_neighbor(addr)) {
return 0;
}
item = memb_alloc(&neighbor_addr_mem);
if(item == NULL) {
return -1;
}
list_push(neighbor_addrs, item);
item->time = 0;
rimeaddr_copy(&item->addr, addr);
/* look up index and set default values */
ptr = neighbor_addr_mem.mem;
for(i = 0; i < neighbor_addr_mem.num; ++i) {
if(&ptr[i] == item) {
break;
}
}
item->index = i;
for(def = list_head(neighbor_attrs); def != NULL; def = def->next) {
set_attr(def, i);
}
return 1;
}
/*---------------------------------------------------------------------------*/
int
neighbor_attr_remove_neighbor(const rimeaddr_t *addr)
{
struct neighbor_addr *item = neighbor_addr_get(addr);
if(item != NULL) {
list_remove(neighbor_addrs, item);
memb_free(&neighbor_addr_mem, item);
return 0;
}
return -1;
}
/*---------------------------------------------------------------------------*/
void *
neighbor_attr_get_data(struct neighbor_attr *def, const rimeaddr_t *addr)
{
struct neighbor_addr *attr = neighbor_addr_get(addr);
if(attr != NULL) {
return (char *)def->data + attr->index * def->size;
}
return NULL;
}
/*---------------------------------------------------------------------------*/
int
neighbor_attr_set_data(struct neighbor_attr *def, const rimeaddr_t *addr,
void *data)
{
struct neighbor_addr *attr = neighbor_addr_get(addr);
if(attr == NULL) {
if(neighbor_attr_add_neighbor(addr)) {
attr = neighbor_addr_get(addr);
}
}
if(attr != NULL) {
attr->time = 0;
memcpy((char *)def->data + attr->index * def->size, data, def->size);
return 1;
}
return 0;
}
/*---------------------------------------------------------------------------*/
void
neighbor_attr_tick(const rimeaddr_t * addr)
{
struct neighbor_addr *attr = neighbor_addr_get(addr);
if(attr != NULL) {
attr->time = 0;
}
}
/*---------------------------------------------------------------------------*/
uint16_t
neighbor_attr_get_timeout(void)
{
return timeout;
}
/*---------------------------------------------------------------------------*/
static struct ctimer ct;
#define TIMEOUT_SECONDS 5
static void
timeout_check(void *ptr)
{
if(timeout > 0) {
struct neighbor_addr *item = neighbor_attr_list_neighbors();
while(item != NULL) {
item->time += TIMEOUT_SECONDS;
if(item->time >= timeout) {
struct neighbor_addr *next_item = item->next;
list_remove(neighbor_addrs, item);
memb_free(&neighbor_addr_mem, item);
item = next_item;
} else {
item = item->next;
}
}
ctimer_set(&ct, TIMEOUT_SECONDS * CLOCK_SECOND, timeout_check, ptr);
}
}
/*---------------------------------------------------------------------------*/
void
neighbor_attr_set_timeout(uint16_t time)
{
if(timeout == 0 && time > 0) {
ctimer_set(&ct, TIMEOUT_SECONDS * CLOCK_SECOND, timeout_check, NULL);
} else if(timeout > 0 && time == 0) {
ctimer_stop(&ct);
}
timeout = time;
}
/*---------------------------------------------------------------------------*/

View file

@ -1,163 +0,0 @@
/*
* Copyright (c) 2010, Vrije Universiteit Brussel
* 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.
*
*
* Author: Joris Borms <joris.borms@vub.ac.be>
*
*/
#ifndef NEIGHBORATTR_H_
#define NEIGHBORATTR_H_
#include "net/rime.h"
/**
* define how many neighbors you can store
*/
#ifdef NEIGHBOR_CONF_MAX_NEIGHBORS
#define NEIGHBOR_ATTR_MAX_NEIGHBORS NEIGHBOR_CONF_MAX_NEIGHBORS
#else /* NEIGHBOR_CONF_MAX_NEIGHBORS */
#define NEIGHBOR_ATTR_MAX_NEIGHBORS 12
#endif /* NEIGHBOR_CONF_MAX_NEIGHBORS */
/**
* \brief properties of a single neighbor
*/
struct neighbor_addr {
struct neighbor_addr *next;
rimeaddr_t addr;
uint16_t time;
uint16_t index;
};
/**
* \brief properties that define a neighbor attribute
*/
struct neighbor_attr {
struct neighbor_attr *next;
uint16_t size;
void *default_value;
void *data;
};
/**
* \brief Define space for additional parameters in neighbor table entries.
* \param type The type of the attribute.
* \param name The name of the attribute.
* \param def A ptr to the default value for this attribute. If NULL, attribute will
* be filled with zeroes by default.
*
* The attribute 'name' should be registered with 'neighbor_attr_register'
* during initialization.
*/
#define NEIGHBOR_ATTRIBUTE(type, name, default_value_ptr) \
static type _##name##_mem[NEIGHBOR_ATTR_MAX_NEIGHBORS]; \
static struct neighbor_attr name = \
{NULL, sizeof(type), default_value_ptr, (void *)_##name##_mem}
/** Same as NEIGHBOR_ATTRIBUTE, only the attr is not declared static
* this way you can say <tt>extern struct neighbor_attr name</tt> in header to declare
* a global neighbor attribute
*/
#define NEIGHBOR_ATTRIBUTE_GLOBAL(type, name, default_value_ptr) \
static type _##name##_mem[NEIGHBOR_ATTR_MAX_NEIGHBORS]; \
struct neighbor_attr name = \
{NULL, sizeof(type), default_value_ptr, (void *)_##name##_mem}
#define NEIGHBOR_ATTRIBUTE_DECLARE(name) extern struct neighbor_attr name
/**
* \brief register a neighbor attribute
* \retval non-zero if successful, zero if not
*/
int neighbor_attr_register(struct neighbor_attr *);
/**
* \retval head of neighbor list, useful for iterating over all neighbors
*/
struct neighbor_addr *neighbor_attr_list_neighbors(void);
/**
* \brief Check if a neighbor is already added to the neighbor table
* \retval non-zero if present, zero if not
*/
int neighbor_attr_has_neighbor(const rimeaddr_t *addr);
/**
* \brief Add a neighbor entry to neighbor table
* \retval -1 if unsuccessful, 0 if the neighbor was already
* in the table, and 1 if successful
*/
int neighbor_attr_add_neighbor(const rimeaddr_t *addr);
/**
* \brief Remove a neighbor entry to neighbor table
* \retval -1 if unsuccessful, 0 if the neighbor was removed
*/
int neighbor_attr_remove_neighbor(const rimeaddr_t *addr);
/**
* \brief Get pointer to neighbor table data specified by id
* \param requested attribute
* \param addr requested neighbor
* \retval pointer to data, NULL if neighbor was not found
*
* Searches neighbor table for addr and returns pointer to data section
* specified by attribute type and addr.
* This pointer should not be saved, as it may point to data from another
* neighbor in the future if neighbors get removed/added over time.
*/
void *neighbor_attr_get_data(struct neighbor_attr *, const rimeaddr_t *addr);
/**
* \brief Copy data to neighbor table
* \retval non-zero if successful, zero if not
*
* Copies data to specific part of the neighbor table, specified by
* neighbor and attribute type, and resets timeout for that neighbor.
* If neighbor was not found, this will add a new neighbor to the table.
*/
int neighbor_attr_set_data(struct neighbor_attr *, const rimeaddr_t *addr,
void *data);
/**
* \brief Set global lifetime of neighbor entries.
* \param Lifetime in seconds. If 0, entries will not time out
*/
void neighbor_attr_set_timeout(uint16_t);
/**
* \brief get global lifetime of neighbor entries. If 0, entries will not time out
*/
uint16_t neighbor_attr_get_timeout(void);
/**
* \brief reset timeout of a neighbor to prevent it from being removed
*/
void neighbor_attr_tick(const rimeaddr_t *);
#endif /* NEIGHBORATTR_H_ */

View file

@ -1,193 +0,0 @@
/*
* Copyright (c) 2010, 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.
*
* This file is part of the Contiki operating system.
*
*/
/**
* \file
* A generic module for management of neighbor information.
*
* \author Nicolas Tsiftes <nvt@sics.se>
*/
#include "net/neighbor-info.h"
#include "net/neighbor-attr.h"
#include "net/uip-ds6.h"
#include "net/uip-nd6.h"
#define DEBUG DEBUG_NONE
#include "net/uip-debug.h"
#define ETX_LIMIT 15
#define ETX_SCALE 100
#define ETX_ALPHA 90
#define ETX_NOACK_PENALTY ETX_LIMIT
/*---------------------------------------------------------------------------*/
NEIGHBOR_ATTRIBUTE_GLOBAL(link_metric_t, attr_etx, NULL);
NEIGHBOR_ATTRIBUTE_GLOBAL(unsigned long, attr_timestamp, NULL);
static neighbor_info_subscriber_t subscriber_callback;
/*---------------------------------------------------------------------------*/
static void
update_metric(const rimeaddr_t *dest, int packet_metric)
{
link_metric_t *metricp;
link_metric_t recorded_metric, new_metric;
unsigned long time;
int first_update = 0;
metricp = (link_metric_t *)neighbor_attr_get_data(&attr_etx, dest);
packet_metric = NEIGHBOR_INFO_ETX2FIX(packet_metric);
if(metricp == NULL || *metricp == 0) {
recorded_metric = NEIGHBOR_INFO_ETX2FIX(ETX_LIMIT);
new_metric = packet_metric;
first_update = 1;
} else {
recorded_metric = *metricp;
/* Update the EWMA of the ETX for the neighbor. */
new_metric = ((uint16_t)recorded_metric * ETX_ALPHA +
(uint16_t)packet_metric * (ETX_SCALE - ETX_ALPHA)) / ETX_SCALE;
}
PRINTF("neighbor-info: ETX changed from %d to %d (packet ETX = %d) %d\n",
NEIGHBOR_INFO_FIX2ETX(recorded_metric),
NEIGHBOR_INFO_FIX2ETX(new_metric),
NEIGHBOR_INFO_FIX2ETX(packet_metric),
dest->u8[7]);
if(neighbor_attr_has_neighbor(dest)) {
time = clock_seconds();
neighbor_attr_set_data(&attr_etx, dest, &new_metric);
neighbor_attr_set_data(&attr_timestamp, dest, &time);
if((first_update || new_metric != recorded_metric) && subscriber_callback != NULL) {
subscriber_callback(dest, 1, new_metric);
}
}
}
/*---------------------------------------------------------------------------*/
static void
add_neighbor(const rimeaddr_t *addr)
{
switch(neighbor_attr_add_neighbor(addr)) {
case -1:
PRINTF("neighbor-info: failed to add a node.\n");
break;
case 0:
PRINTF("neighbor-info: The neighbor is already known\n");
break;
default:
break;
}
}
/*---------------------------------------------------------------------------*/
void
neighbor_info_packet_sent(int status, int numtx)
{
const rimeaddr_t *dest;
link_metric_t packet_metric;
#if UIP_DS6_LL_NUD
uip_ds6_nbr_t *nbr;
#endif /* UIP_DS6_LL_NUD */
dest = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
if(rimeaddr_cmp(dest, &rimeaddr_null)) {
return;
}
packet_metric = numtx;
PRINTF("neighbor-info: packet sent to %d.%d, status=%d, metric=%u\n",
dest->u8[sizeof(*dest) - 2], dest->u8[sizeof(*dest) - 1],
status, (unsigned)packet_metric);
switch(status) {
case MAC_TX_OK:
add_neighbor(dest);
#if UIP_DS6_LL_NUD
nbr = uip_ds6_nbr_ll_lookup((uip_lladdr_t *)dest);
if(nbr != NULL &&
(nbr->state == STALE || nbr->state == DELAY || nbr->state == PROBE)) {
nbr->state = REACHABLE;
stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
PRINTF("neighbor-info : received a link layer ACK : ");
PRINTLLADDR((uip_lladdr_t *)dest);
PRINTF(" is reachable.\n");
}
#endif /* UIP_DS6_LL_NUD */
break;
case MAC_TX_NOACK:
packet_metric = ETX_NOACK_PENALTY;
break;
default:
/* Do not penalize the ETX when collisions or transmission
errors occur. */
return;
}
update_metric(dest, packet_metric);
}
/*---------------------------------------------------------------------------*/
void
neighbor_info_packet_received(void)
{
const rimeaddr_t *src;
src = packetbuf_addr(PACKETBUF_ADDR_SENDER);
if(rimeaddr_cmp(src, &rimeaddr_null)) {
return;
}
PRINTF("neighbor-info: packet received from %d.%d\n",
src->u8[sizeof(*src) - 2], src->u8[sizeof(*src) - 1]);
add_neighbor(src);
}
/*---------------------------------------------------------------------------*/
int
neighbor_info_subscribe(neighbor_info_subscriber_t s)
{
if(subscriber_callback == NULL) {
neighbor_attr_register(&attr_etx);
neighbor_attr_register(&attr_timestamp);
subscriber_callback = s;
return 1;
}
return 0;
}
/*---------------------------------------------------------------------------*/
link_metric_t
neighbor_info_get_metric(const rimeaddr_t *addr)
{
link_metric_t *metricp;
metricp = (link_metric_t *)neighbor_attr_get_data(&attr_etx, addr);
return metricp == NULL ? ETX_LIMIT : *metricp;
}
/*---------------------------------------------------------------------------*/

View file

@ -1,94 +0,0 @@
/*
* Copyright (c) 2010, 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.
*
* This file is part of the Contiki operating system.
*
*/
/**
* \file
* Declarations for the neighbor information module.
*
* \author Nicolas Tsiftes <nvt@sics.se>
*/
#ifndef NEIGHBOR_INFO_H
#define NEIGHBOR_INFO_H
#include "net/neighbor-attr.h"
#include "net/rime.h"
/* ETX_DIVISOR is the value that a fix-point representation of the ETX
should be divided by in order to obtain the integer representation. */
#define NEIGHBOR_INFO_ETX_DIVISOR 16
/* Macros for converting between a fix-point representation of the ETX
and a integer representation. */
#define NEIGHBOR_INFO_ETX2FIX(etx) ((etx) * NEIGHBOR_INFO_ETX_DIVISOR)
#define NEIGHBOR_INFO_FIX2ETX(fix) ((fix) / NEIGHBOR_INFO_ETX_DIVISOR)
typedef void (*neighbor_info_subscriber_t)(const rimeaddr_t *, int known, int etx);
typedef uint8_t link_metric_t;
NEIGHBOR_ATTRIBUTE_DECLARE(attr_etx);
NEIGHBOR_ATTRIBUTE_DECLARE(attr_timestamp);
/**
* Notify the neighbor information module about the status of
* a packet transmission.
*
* \param status The MAC status code for this packet.
*
* \param numtx The amount of transmissions made for this packet.
*/
void neighbor_info_packet_sent(int status, int numtx);
/**
* Notify the neighbor information module that a packet was received.
*
* \param status The MAC status code for this packet.
*
* \param numtx The amount of transmissions made for this packet.
*/
void neighbor_info_packet_received(void);
/**
* Subscribe to notifications of changed neighbor information.
*
* \return Returns 1 if the subscription was successful, and 0 if not.
*/
int neighbor_info_subscribe(neighbor_info_subscriber_t);
/**
* Get link metric value for a specific neighbor.
*
* \return Returns link metric if the neighbor exists, and 0 if not.
*/
link_metric_t neighbor_info_get_metric(const rimeaddr_t *addr);
#endif /* NEIGHBOR_INFO_H */

View file

@ -162,9 +162,9 @@
* Initial metric attributed to a link when the ETX is unknown * Initial metric attributed to a link when the ETX is unknown
*/ */
#ifndef RPL_CONF_INIT_LINK_METRIC #ifndef RPL_CONF_INIT_LINK_METRIC
#define RPL_INIT_LINK_METRIC NEIGHBOR_INFO_ETX2FIX(5) #define RPL_INIT_LINK_METRIC 5 * RPL_MIN_HOPRANKINC
#else #else
#define RPL_INIT_LINK_METRIC NEIGHBOR_INFO_ETX2FIX(RPL_CONF_INIT_LINK_METRIC) #define RPL_INIT_LINK_METRIC RPL_CONF_INIT_LINK_METRIC
#endif #endif
/* /*

View file

@ -56,8 +56,6 @@
#define DEBUG DEBUG_NONE #define DEBUG DEBUG_NONE
#include "net/uip-debug.h" #include "net/uip-debug.h"
#include "net/neighbor-info.h"
#if UIP_CONF_IPV6 #if UIP_CONF_IPV6
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
extern rpl_of_t RPL_OF; extern rpl_of_t RPL_OF;

View file

@ -45,13 +45,13 @@
*/ */
#include "net/rpl/rpl-private.h" #include "net/rpl/rpl-private.h"
#include "net/neighbor-info.h" #include "net/neighbor-table.h"
#define DEBUG DEBUG_NONE #define DEBUG DEBUG_NONE
#include "net/uip-debug.h" #include "net/uip-debug.h"
static void reset(rpl_dag_t *); static void reset(rpl_dag_t *);
static void parent_state_callback(rpl_parent_t *, int, int); static void neighbor_link_callback(rpl_parent_t *, int, int);
static rpl_parent_t *best_parent(rpl_parent_t *, rpl_parent_t *); static rpl_parent_t *best_parent(rpl_parent_t *, rpl_parent_t *);
static rpl_dag_t *best_dag(rpl_dag_t *, rpl_dag_t *); static rpl_dag_t *best_dag(rpl_dag_t *, rpl_dag_t *);
static rpl_rank_t calculate_rank(rpl_parent_t *, rpl_rank_t); static rpl_rank_t calculate_rank(rpl_parent_t *, rpl_rank_t);
@ -59,7 +59,7 @@ static void update_metric_container(rpl_instance_t *);
rpl_of_t rpl_mrhof = { rpl_of_t rpl_mrhof = {
reset, reset,
parent_state_callback, neighbor_link_callback,
best_parent, best_parent,
best_dag, best_dag,
calculate_rank, calculate_rank,
@ -67,6 +67,10 @@ rpl_of_t rpl_mrhof = {
1 1
}; };
/* Constants for the ETX moving average */
#define ETX_SCALE 100
#define ETX_ALPHA 90
/* Reject parents that have a higher link metric than the following. */ /* Reject parents that have a higher link metric than the following. */
#define MAX_LINK_METRIC 10 #define MAX_LINK_METRIC 10
@ -88,7 +92,6 @@ calculate_path_metric(rpl_parent_t *p)
return MAX_PATH_COST * RPL_DAG_MC_ETX_DIVISOR; return MAX_PATH_COST * RPL_DAG_MC_ETX_DIVISOR;
} else { } else {
long link_metric = p->link_metric; long link_metric = p->link_metric;
link_metric = (link_metric * RPL_DAG_MC_ETX_DIVISOR) / NEIGHBOR_INFO_ETX_DIVISOR;
#if RPL_DAG_MC == RPL_DAG_MC_NONE #if RPL_DAG_MC == RPL_DAG_MC_NONE
return p->rank + (uint16_t)link_metric; return p->rank + (uint16_t)link_metric;
#elif RPL_DAG_MC == RPL_DAG_MC_ETX #elif RPL_DAG_MC == RPL_DAG_MC_ETX
@ -105,8 +108,29 @@ reset(rpl_dag_t *sag)
} }
static void static void
parent_state_callback(rpl_parent_t *parent, int known, int etx) neighbor_link_callback(rpl_parent_t *p, int status, int numtx)
{ {
/* Do not penalize the ETX when collisions or transmission errors occur. */
if(status == MAC_TX_OK || status == MAC_TX_NOACK) {
int recorded_etx = p->link_metric;
int packet_etx = numtx;
int new_etx;
if(status == MAC_TX_NOACK) {
packet_etx = MAX_LINK_METRIC;
}
new_etx = ((uint16_t)recorded_etx * ETX_ALPHA +
(uint16_t)packet_etx * (ETX_SCALE - ETX_ALPHA)) / ETX_SCALE;
PRINTF("RPL: ETX changed from %d to %d (packet ETX = %d) %d\n",
recorded_etx / p->dag->instance->min_hoprankinc,
new_etx / p->dag->instance->min_hoprankinc,
packet_etx / p->dag->instance->min_hoprankinc,
dest->u8[7]);
p->link_metric = new_etx;
}
} }
static rpl_rank_t static rpl_rank_t
@ -119,10 +143,10 @@ calculate_rank(rpl_parent_t *p, rpl_rank_t base_rank)
if(base_rank == 0) { if(base_rank == 0) {
return INFINITE_RANK; return INFINITE_RANK;
} }
rank_increase = NEIGHBOR_INFO_FIX2ETX(RPL_INIT_LINK_METRIC) * RPL_MIN_HOPRANKINC; rank_increase = RPL_INIT_LINK_METRIC;
} else { } else {
/* multiply first, then scale down to avoid truncation effects */ /* multiply first, then scale down to avoid truncation effects */
rank_increase = NEIGHBOR_INFO_FIX2ETX(p->link_metric * p->dag->instance->min_hoprankinc); rank_increase = p->link_metric;
if(base_rank == 0) { if(base_rank == 0) {
base_rank = p->rank; base_rank = p->rank;
} }

View file

@ -44,8 +44,6 @@
#define DEBUG DEBUG_NONE #define DEBUG DEBUG_NONE
#include "net/uip-debug.h" #include "net/uip-debug.h"
#include "net/neighbor-info.h"
static void reset(rpl_dag_t *); static void reset(rpl_dag_t *);
static rpl_parent_t *best_parent(rpl_parent_t *, rpl_parent_t *); static rpl_parent_t *best_parent(rpl_parent_t *, rpl_parent_t *);
static rpl_dag_t *best_dag(rpl_dag_t *, rpl_dag_t *); static rpl_dag_t *best_dag(rpl_dag_t *, rpl_dag_t *);
@ -64,7 +62,7 @@ rpl_of_t rpl_of0 = {
#define DEFAULT_RANK_INCREMENT RPL_MIN_HOPRANKINC #define DEFAULT_RANK_INCREMENT RPL_MIN_HOPRANKINC
#define MIN_DIFFERENCE (NEIGHBOR_INFO_ETX_DIVISOR + NEIGHBOR_INFO_ETX_DIVISOR / 2) #define MIN_DIFFERENCE (RPL_MIN_HOPRANKINC + RPL_MIN_HOPRANKINC / 2)
static void static void
reset(rpl_dag_t *dag) reset(rpl_dag_t *dag)
@ -137,9 +135,9 @@ best_parent(rpl_parent_t *p1, rpl_parent_t *p2)
p2->link_metric, p2->rank); p2->link_metric, p2->rank);
r1 = DAG_RANK(p1->rank, p1->dag->instance) * NEIGHBOR_INFO_ETX_DIVISOR + r1 = DAG_RANK(p1->rank, p1->dag->instance) * RPL_MIN_HOPRANKINC +
p1->link_metric; p1->link_metric;
r2 = DAG_RANK(p2->rank, p1->dag->instance) * NEIGHBOR_INFO_ETX_DIVISOR + r2 = DAG_RANK(p2->rank, p1->dag->instance) * RPL_MIN_HOPRANKINC +
p2->link_metric; p2->link_metric;
/* Compare two parents by looking both and their rank and at the ETX /* Compare two parents by looking both and their rank and at the ETX
for that parent. We choose the parent that has the most for that parent. We choose the parent that has the most

View file

@ -44,7 +44,6 @@
#include "net/tcpip.h" #include "net/tcpip.h"
#include "net/uip-ds6.h" #include "net/uip-ds6.h"
#include "net/rpl/rpl-private.h" #include "net/rpl/rpl-private.h"
#include "net/neighbor-info.h"
#define DEBUG DEBUG_NONE #define DEBUG DEBUG_NONE
#include "net/uip-debug.h" #include "net/uip-debug.h"
@ -168,8 +167,8 @@ rpl_add_route(rpl_dag_t *dag, uip_ipaddr_t *prefix, int prefix_len,
return rep; return rep;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void void
rpl_link_neighbor_callback(const rimeaddr_t *addr, int known, int etx) rpl_link_neighbor_callback(const rimeaddr_t *addr, int status, int numtx)
{ {
uip_ipaddr_t ipaddr; uip_ipaddr_t ipaddr;
rpl_parent_t *parent; rpl_parent_t *parent;
@ -178,9 +177,6 @@ rpl_link_neighbor_callback(const rimeaddr_t *addr, int known, int etx)
uip_ip6addr(&ipaddr, 0xfe80, 0, 0, 0, 0, 0, 0, 0); uip_ip6addr(&ipaddr, 0xfe80, 0, 0, 0, 0, 0, 0, 0);
uip_ds6_set_addr_iid(&ipaddr, (uip_lladdr_t *)addr); uip_ds6_set_addr_iid(&ipaddr, (uip_lladdr_t *)addr);
PRINTF("RPL: Neighbor ");
PRINT6ADDR(&ipaddr);
PRINTF(" is %sknown. ETX = %u\n", known ? "" : "no longer ", NEIGHBOR_INFO_FIX2ETX(etx));
for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES; instance < end; ++instance) { for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES; instance < end; ++instance) {
if(instance->used == 1 ) { if(instance->used == 1 ) {
@ -188,27 +184,12 @@ rpl_link_neighbor_callback(const rimeaddr_t *addr, int known, int etx)
if(parent != NULL) { if(parent != NULL) {
/* Trigger DAG rank recalculation. */ /* Trigger DAG rank recalculation. */
parent->updated = 1; parent->updated = 1;
parent->link_metric = etx; if(instance->of->neighbor_link_callback != NULL) {
instance->of->neighbor_link_callback(parent, status, numtx);
if(instance->of->parent_state_callback != NULL) {
instance->of->parent_state_callback(parent, known, etx);
}
if(!known) {
PRINTF("RPL: Removing parent ");
PRINT6ADDR(&parent->addr);
PRINTF(" in instance %u because of bad connectivity (ETX %d)\n", instance->instance_id, etx);
parent->rank = INFINITE_RANK;
} }
} }
} }
} }
if(!known) {
PRINTF("RPL: Deleting routes installed by DAOs received from ");
PRINT6ADDR(&ipaddr);
PRINTF("\n");
uip_ds6_route_rm_by_nexthop(&ipaddr);
}
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void void
@ -242,7 +223,6 @@ rpl_init(void)
rpl_dag_init(); rpl_dag_init();
rpl_reset_periodic_timer(); rpl_reset_periodic_timer();
neighbor_info_subscribe(rpl_link_neighbor_callback);
/* add rpl multicast address */ /* add rpl multicast address */
uip_create_linklocal_rplnodes_mcast(&rplmaddr); uip_create_linklocal_rplnodes_mcast(&rplmaddr);

View file

@ -156,7 +156,7 @@ typedef struct rpl_instance rpl_instance_t;
* Resets the objective function state for a specific DAG. This function is * Resets the objective function state for a specific DAG. This function is
* called when doing a global repair on the DAG. * called when doing a global repair on the DAG.
* *
* parent_state_callback(parent, known, etx) * neighbor_link_callback(parent, known, etx)
* *
* Receives link-layer neighbor information. The parameter "known" is set * Receives link-layer neighbor information. The parameter "known" is set
* either to 0 or 1. The "etx" parameter specifies the current * either to 0 or 1. The "etx" parameter specifies the current
@ -185,7 +185,7 @@ typedef struct rpl_instance rpl_instance_t;
*/ */
struct rpl_of { struct rpl_of {
void (*reset)(struct rpl_dag *); void (*reset)(struct rpl_dag *);
void (*parent_state_callback)(rpl_parent_t *, int, int); void (*neighbor_link_callback)(rpl_parent_t *, int, int);
rpl_parent_t *(*best_parent)(rpl_parent_t *, rpl_parent_t *); rpl_parent_t *(*best_parent)(rpl_parent_t *, rpl_parent_t *);
rpl_dag_t *(*best_dag)(rpl_dag_t *, rpl_dag_t *); rpl_dag_t *(*best_dag)(rpl_dag_t *, rpl_dag_t *);
rpl_rank_t (*calculate_rank)(rpl_parent_t *, rpl_rank_t); rpl_rank_t (*calculate_rank)(rpl_parent_t *, rpl_rank_t);

View file

@ -65,7 +65,6 @@
#include "net/uip-ds6.h" #include "net/uip-ds6.h"
#include "net/rime.h" #include "net/rime.h"
#include "net/sicslowpan.h" #include "net/sicslowpan.h"
#include "net/neighbor-info.h"
#include "net/netstack.h" #include "net/netstack.h"
#if UIP_CONF_IPV6 #if UIP_CONF_IPV6
@ -113,11 +112,6 @@ void uip_log(char *msg);
#endif /* SICSLOWPAN_CONF_COMPRESSION */ #endif /* SICSLOWPAN_CONF_COMPRESSION */
#endif /* SICSLOWPAN_COMPRESSION */ #endif /* SICSLOWPAN_COMPRESSION */
#ifndef SICSLOWPAN_CONF_NEIGHBOR_INFO
/* Default is to use neighbor info updates if using RPL */
#define SICSLOWPAN_CONF_NEIGHBOR_INFO UIP_CONF_IPV6_RPL
#endif /* SICSLOWPAN_CONF_NEIGHBOR_INFO */
#define GET16(ptr,index) (((uint16_t)((ptr)[index] << 8)) | ((ptr)[(index) + 1])) #define GET16(ptr,index) (((uint16_t)((ptr)[index] << 8)) | ((ptr)[(index) + 1]))
#define SET16(ptr,index,value) do { \ #define SET16(ptr,index,value) do { \
(ptr)[index] = ((value) >> 8) & 0xff; \ (ptr)[index] = ((value) >> 8) & 0xff; \
@ -1309,9 +1303,8 @@ compress_hdr_ipv6(rimeaddr_t *rime_destaddr)
static void static void
packet_sent(void *ptr, int status, int transmissions) packet_sent(void *ptr, int status, int transmissions)
{ {
#if SICSLOWPAN_CONF_NEIGHBOR_INFO uip_ds6_link_neighbor_callback(status, transmissions);
neighbor_info_packet_sent(status, transmissions);
#endif /* SICSLOWPAN_CONF_NEIGHBOR_INFO */
if(callback != NULL) { if(callback != NULL) {
callback->output_callback(status); callback->output_callback(status);
} }
@ -1834,10 +1827,6 @@ input(void)
} }
#endif #endif
#if SICSLOWPAN_CONF_NEIGHBOR_INFO
neighbor_info_packet_received();
#endif /* SICSLOWPAN_CONF_NEIGHBOR_INFO */
/* if callback is set then set attributes and call */ /* if callback is set then set attributes and call */
if(callback) { if(callback) {
set_packet_attrs(); set_packet_attrs();

View file

@ -61,6 +61,13 @@ void NEIGHBOR_STATE_CHANGED(uip_ds6_nbr_t *n);
#define NEIGHBOR_STATE_CHANGED(n) #define NEIGHBOR_STATE_CHANGED(n)
#endif /* UIP_DS6_CONF_NEIGHBOR_STATE_CHANGED */ #endif /* UIP_DS6_CONF_NEIGHBOR_STATE_CHANGED */
#ifdef UIP_CONF_DS6_LINK_NEIGHBOR_CALLBACK
#define LINK_NEIGHBOR_CALLBACK(addr, status, numtx) UIP_CONF_DS6_LINK_NEIGHBOR_CALLBACK(addr, status, numtx)
void LINK_NEIGHBOR_CALLBACK(const rimeaddr_t *addr, int status, int numtx);
#else
#define LINK_NEIGHBOR_CALLBACK(addr, status, numtx)
#endif /* UIP_CONF_DS6_LINK_NEIGHBOR_CALLBACK */
NEIGHBOR_TABLE_GLOBAL(uip_ds6_nbr_t, ds6_neighbors); NEIGHBOR_TABLE_GLOBAL(uip_ds6_nbr_t, ds6_neighbors);
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
@ -166,6 +173,33 @@ uip_ds6_nbr_lladdr_from_ipaddr(uip_ipaddr_t *ipaddr)
uip_ds6_nbr_t *nbr = uip_ds6_nbr_lookup(ipaddr); uip_ds6_nbr_t *nbr = uip_ds6_nbr_lookup(ipaddr);
return nbr ? uip_ds6_nbr_get_ll(nbr) : NULL; return nbr ? uip_ds6_nbr_get_ll(nbr) : NULL;
} }
/*---------------------------------------------------------------------------*/
void
uip_ds6_link_neighbor_callback(int status, int numtx)
{
const rimeaddr_t *dest = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
if(rimeaddr_cmp(dest, &rimeaddr_null)) {
return;
}
LINK_NEIGHBOR_CALLBACK(dest, status, numtx);
#if UIP_DS6_LL_NUD
if(status == MAC_TX_OK) {
uip_ds6_nbr_t *nbr;
nbr = uip_ds6_nbr_ll_lookup((uip_lladdr_t *)dest);
if(nbr != NULL &&
(nbr->state == STALE || nbr->state == DELAY || nbr->state == PROBE)) {
nbr->state = REACHABLE;
stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
PRINTF("uip-ds6-neighbor : received a link layer ACK : ");
PRINTLLADDR((uip_lladdr_t *)dest);
PRINTF(" is reachable.\n");
}
}
#endif /* UIP_DS6_LL_NUD */
}
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void void

View file

@ -81,6 +81,7 @@ uip_ds6_nbr_t *uip_ds6_nbr_lookup(uip_ipaddr_t *ipaddr);
uip_ds6_nbr_t *uip_ds6_nbr_ll_lookup(uip_lladdr_t *lladdr); uip_ds6_nbr_t *uip_ds6_nbr_ll_lookup(uip_lladdr_t *lladdr);
uip_ipaddr_t *uip_ds6_nbr_ipaddr_from_lladdr(uip_lladdr_t *lladdr); uip_ipaddr_t *uip_ds6_nbr_ipaddr_from_lladdr(uip_lladdr_t *lladdr);
uip_lladdr_t *uip_ds6_nbr_lladdr_from_ipaddr(uip_ipaddr_t *ipaddr); uip_lladdr_t *uip_ds6_nbr_lladdr_from_ipaddr(uip_ipaddr_t *ipaddr);
void uip_ds6_link_neighbor_callback(int status, int numtx);
void uip_ds6_neighbor_periodic(); void uip_ds6_neighbor_periodic();
/** /**

View file

@ -203,6 +203,13 @@ typedef struct uip_ds6_maddr {
#endif /* UIP_CONF_DS6_NEIGHBOR_STATE_CHANGED */ #endif /* UIP_CONF_DS6_NEIGHBOR_STATE_CHANGED */
#endif /* UIP_CONF_IPV6_RPL */ #endif /* UIP_CONF_IPV6_RPL */
#if UIP_CONF_IPV6_RPL
#ifndef UIP_CONF_DS6_LINK_NEIGHBOR_CALLBACK
#define UIP_CONF_DS6_LINK_NEIGHBOR_CALLBACK rpl_link_neighbor_callback
#endif /* UIP_CONF_DS6_NEIGHBOR_STATE_CHANGED */
#endif /* UIP_CONF_IPV6_RPL */
/** \brief Interface structure (contains all the interface variables) */ /** \brief Interface structure (contains all the interface variables) */
typedef struct uip_ds6_netif { typedef struct uip_ds6_netif {
uint32_t link_mtu; uint32_t link_mtu;