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 = \
dhcpc.c \
hc.c \
neighbor-attr.c \
neighbor-info.c \
neighbor-table.c \
netstack.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
*/
#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
#define RPL_INIT_LINK_METRIC NEIGHBOR_INFO_ETX2FIX(RPL_CONF_INIT_LINK_METRIC)
#define RPL_INIT_LINK_METRIC RPL_CONF_INIT_LINK_METRIC
#endif
/*

View File

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

View File

@ -45,13 +45,13 @@
*/
#include "net/rpl/rpl-private.h"
#include "net/neighbor-info.h"
#include "net/neighbor-table.h"
#define DEBUG DEBUG_NONE
#include "net/uip-debug.h"
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_dag_t *best_dag(rpl_dag_t *, rpl_dag_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 = {
reset,
parent_state_callback,
neighbor_link_callback,
best_parent,
best_dag,
calculate_rank,
@ -67,6 +67,10 @@ rpl_of_t rpl_mrhof = {
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. */
#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;
} else {
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
return p->rank + (uint16_t)link_metric;
#elif RPL_DAG_MC == RPL_DAG_MC_ETX
@ -105,8 +108,29 @@ reset(rpl_dag_t *sag)
}
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
@ -119,10 +143,10 @@ calculate_rank(rpl_parent_t *p, rpl_rank_t base_rank)
if(base_rank == 0) {
return INFINITE_RANK;
}
rank_increase = NEIGHBOR_INFO_FIX2ETX(RPL_INIT_LINK_METRIC) * RPL_MIN_HOPRANKINC;
rank_increase = RPL_INIT_LINK_METRIC;
} else {
/* 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) {
base_rank = p->rank;
}

View File

@ -44,8 +44,6 @@
#define DEBUG DEBUG_NONE
#include "net/uip-debug.h"
#include "net/neighbor-info.h"
static void reset(rpl_dag_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 *);
@ -64,7 +62,7 @@ rpl_of_t rpl_of0 = {
#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
reset(rpl_dag_t *dag)
@ -137,9 +135,9 @@ best_parent(rpl_parent_t *p1, rpl_parent_t *p2)
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;
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;
/* Compare two parents by looking both and their rank and at the ETX
for that parent. We choose the parent that has the most

View File

@ -44,7 +44,6 @@
#include "net/tcpip.h"
#include "net/uip-ds6.h"
#include "net/rpl/rpl-private.h"
#include "net/neighbor-info.h"
#define DEBUG DEBUG_NONE
#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;
}
/*---------------------------------------------------------------------------*/
static void
rpl_link_neighbor_callback(const rimeaddr_t *addr, int known, int etx)
void
rpl_link_neighbor_callback(const rimeaddr_t *addr, int status, int numtx)
{
uip_ipaddr_t ipaddr;
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_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) {
if(instance->used == 1 ) {
@ -188,27 +184,12 @@ rpl_link_neighbor_callback(const rimeaddr_t *addr, int known, int etx)
if(parent != NULL) {
/* Trigger DAG rank recalculation. */
parent->updated = 1;
parent->link_metric = etx;
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(instance->of->neighbor_link_callback != NULL) {
instance->of->neighbor_link_callback(parent, status, numtx);
}
}
}
}
if(!known) {
PRINTF("RPL: Deleting routes installed by DAOs received from ");
PRINT6ADDR(&ipaddr);
PRINTF("\n");
uip_ds6_route_rm_by_nexthop(&ipaddr);
}
}
/*---------------------------------------------------------------------------*/
void
@ -242,7 +223,6 @@ rpl_init(void)
rpl_dag_init();
rpl_reset_periodic_timer();
neighbor_info_subscribe(rpl_link_neighbor_callback);
/* add rpl multicast address */
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
* 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
* 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 {
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_dag_t *(*best_dag)(rpl_dag_t *, rpl_dag_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/rime.h"
#include "net/sicslowpan.h"
#include "net/neighbor-info.h"
#include "net/netstack.h"
#if UIP_CONF_IPV6
@ -113,11 +112,6 @@ void uip_log(char *msg);
#endif /* SICSLOWPAN_CONF_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 SET16(ptr,index,value) do { \
(ptr)[index] = ((value) >> 8) & 0xff; \
@ -1309,9 +1303,8 @@ compress_hdr_ipv6(rimeaddr_t *rime_destaddr)
static void
packet_sent(void *ptr, int status, int transmissions)
{
#if SICSLOWPAN_CONF_NEIGHBOR_INFO
neighbor_info_packet_sent(status, transmissions);
#endif /* SICSLOWPAN_CONF_NEIGHBOR_INFO */
uip_ds6_link_neighbor_callback(status, transmissions);
if(callback != NULL) {
callback->output_callback(status);
}
@ -1834,10 +1827,6 @@ input(void)
}
#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) {
set_packet_attrs();

View File

@ -61,6 +61,13 @@ void NEIGHBOR_STATE_CHANGED(uip_ds6_nbr_t *n);
#define NEIGHBOR_STATE_CHANGED(n)
#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);
/*---------------------------------------------------------------------------*/
@ -166,6 +173,33 @@ uip_ds6_nbr_lladdr_from_ipaddr(uip_ipaddr_t *ipaddr)
uip_ds6_nbr_t *nbr = uip_ds6_nbr_lookup(ipaddr);
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

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_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);
void uip_ds6_link_neighbor_callback(int status, int numtx);
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_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) */
typedef struct uip_ds6_netif {
uint32_t link_mtu;