Rehauling of RPL OFs, both MRHOF and OF0. Fixed compliance with RFC6551, 6552, 6719. Now using the link-stats module.
This commit is contained in:
parent
752fef9e42
commit
426e10c3ed
@ -71,7 +71,6 @@ typedef struct uip_ds6_nbr {
|
||||
uip_ipaddr_t ipaddr;
|
||||
uint8_t isrouter;
|
||||
uint8_t state;
|
||||
uint16_t link_metric;
|
||||
#if UIP_ND6_SEND_NA || UIP_ND6_SEND_RA
|
||||
struct stimer reachable;
|
||||
struct stimer sendns;
|
||||
|
@ -52,6 +52,13 @@
|
||||
* When MRHOF (RFC6719) is used with ETX, no metric container must
|
||||
* be used; instead the rank carries ETX directly.
|
||||
*/
|
||||
#ifdef RPL_CONF_WITH_MC
|
||||
#define RPL_WITH_MC RPL_CONF_WITH_MC
|
||||
#else /* RPL_CONF_WITH_MC */
|
||||
#define RPL_WITH_MC 0
|
||||
#endif /* RPL_CONF_WITH_MC */
|
||||
|
||||
/* The MC advertised in DIOs and propagating from the root */
|
||||
#ifdef RPL_CONF_DAG_MC
|
||||
#define RPL_DAG_MC RPL_CONF_DAG_MC
|
||||
#else
|
||||
@ -186,15 +193,6 @@
|
||||
#define RPL_DIO_REDUNDANCY 10
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initial metric attributed to a link when the ETX is unknown
|
||||
*/
|
||||
#ifndef RPL_CONF_INIT_LINK_METRIC
|
||||
#define RPL_INIT_LINK_METRIC 2
|
||||
#else
|
||||
#define RPL_INIT_LINK_METRIC RPL_CONF_INIT_LINK_METRIC
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Default route lifetime unit. This is the granularity of time
|
||||
* used in RPL lifetime values, in seconds.
|
||||
@ -287,15 +285,6 @@
|
||||
#define RPL_PROBING_INTERVAL (120 * CLOCK_SECOND)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* RPL probing expiration time.
|
||||
*/
|
||||
#ifdef RPL_CONF_PROBING_EXPIRATION_TIME
|
||||
#define RPL_PROBING_EXPIRATION_TIME RPL_CONF_PROBING_EXPIRATION_TIME
|
||||
#else
|
||||
#define RPL_PROBING_EXPIRATION_TIME (10 * 60 * CLOCK_SECOND)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Function used to select the next parent to be probed.
|
||||
*/
|
||||
|
@ -44,6 +44,7 @@
|
||||
*/
|
||||
|
||||
#include "contiki.h"
|
||||
#include "net/link-stats.h"
|
||||
#include "net/rpl/rpl-private.h"
|
||||
#include "net/ip/uip.h"
|
||||
#include "net/ipv6/uip-nd6.h"
|
||||
@ -91,22 +92,25 @@ void
|
||||
rpl_print_neighbor_list(void)
|
||||
{
|
||||
if(default_instance != NULL && default_instance->current_dag != NULL &&
|
||||
default_instance->of != NULL && default_instance->of->calculate_rank != NULL) {
|
||||
default_instance->of != NULL) {
|
||||
int curr_dio_interval = default_instance->dio_intcurrent;
|
||||
int curr_rank = default_instance->current_dag->rank;
|
||||
rpl_parent_t *p = nbr_table_head(rpl_parents);
|
||||
clock_time_t now = clock_time();
|
||||
const struct link_stats *stats = rpl_get_parent_link_stats(p);
|
||||
|
||||
printf("RPL: rank %u dioint %u, %u nbr(s)\n", curr_rank, curr_dio_interval, uip_ds6_nbr_num());
|
||||
printf("RPL: OCP %u rank %u dioint %u, nbr count %u\n",
|
||||
default_instance->of->ocp, curr_rank, curr_dio_interval, uip_ds6_nbr_num());
|
||||
while(p != NULL) {
|
||||
uip_ds6_nbr_t *nbr = rpl_get_nbr(p);
|
||||
printf("RPL: nbr %3u %5u, %5u => %5u %c%c (last tx %u min ago)\n",
|
||||
nbr_table_get_lladdr(rpl_parents, p)->u8[7],
|
||||
p->rank, nbr ? nbr->link_metric : 0,
|
||||
default_instance->of->calculate_rank(p, 0),
|
||||
default_instance->current_dag == p->dag ? 'd' : ' ',
|
||||
p == default_instance->current_dag->preferred_parent ? '*' : ' ',
|
||||
(unsigned)((now - p->last_tx_time) / (60 * CLOCK_SECOND)));
|
||||
printf("RPL: nbr %3u %5u, %5u => %5u -- %5u %c%c (last tx %u min ago)\n",
|
||||
rpl_get_parent_ipaddr(p)->u8[15],
|
||||
p->rank,
|
||||
rpl_get_parent_link_metric(p),
|
||||
rpl_rank_via_parent(p),
|
||||
stats != NULL ? stats->freshness : 0,
|
||||
link_stats_is_fresh(stats) ? 'f' : ' ',
|
||||
p == default_instance->current_dag->preferred_parent ? 'p' : ' ',
|
||||
(unsigned)((now - p->last_tx_time) / (60 * CLOCK_SECOND))
|
||||
);
|
||||
p = nbr_table_next(rpl_parents, p);
|
||||
}
|
||||
printf("RPL: end of list\n");
|
||||
@ -151,30 +155,61 @@ rpl_get_parent_rank(uip_lladdr_t *addr)
|
||||
if(p != NULL) {
|
||||
return p->rank;
|
||||
} else {
|
||||
return 0;
|
||||
return INFINITE_RANK;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uint16_t
|
||||
rpl_get_parent_link_metric(const uip_lladdr_t *addr)
|
||||
rpl_get_parent_link_metric(rpl_parent_t *p)
|
||||
{
|
||||
uip_ds6_nbr_t *nbr;
|
||||
nbr = nbr_table_get_from_lladdr(ds6_neighbors, (const linkaddr_t *)addr);
|
||||
|
||||
if(nbr != NULL) {
|
||||
return nbr->link_metric;
|
||||
} else {
|
||||
return 0;
|
||||
if(p != NULL && p->dag != NULL) {
|
||||
rpl_instance_t *instance = p->dag->instance;
|
||||
if(instance != NULL && instance->of != NULL && instance->of->parent_link_metric != NULL) {
|
||||
return instance->of->parent_link_metric(p);
|
||||
}
|
||||
}
|
||||
return 0xffff;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
rpl_rank_t
|
||||
rpl_rank_via_parent(rpl_parent_t *p)
|
||||
{
|
||||
if(p != NULL && p->dag != NULL) {
|
||||
rpl_instance_t *instance = p->dag->instance;
|
||||
if(instance != NULL && instance->of != NULL && instance->of->rank_via_parent != NULL) {
|
||||
return instance->of->rank_via_parent(p);
|
||||
}
|
||||
}
|
||||
return INFINITE_RANK;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
const linkaddr_t *
|
||||
rpl_get_parent_lladdr(rpl_parent_t *p)
|
||||
{
|
||||
return nbr_table_get_lladdr(rpl_parents, p);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uip_ipaddr_t *
|
||||
rpl_get_parent_ipaddr(rpl_parent_t *p)
|
||||
{
|
||||
linkaddr_t *lladdr = nbr_table_get_lladdr(rpl_parents, p);
|
||||
const linkaddr_t *lladdr = rpl_get_parent_lladdr(p);
|
||||
return uip_ds6_nbr_ipaddr_from_lladdr((uip_lladdr_t *)lladdr);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
const struct link_stats *
|
||||
rpl_get_parent_link_stats(rpl_parent_t *p)
|
||||
{
|
||||
const linkaddr_t *lladdr = rpl_get_parent_lladdr(p);
|
||||
return link_stats_from_lladdr(lladdr);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
rpl_parent_is_fresh(rpl_parent_t *p)
|
||||
{
|
||||
const struct link_stats *stats = rpl_get_parent_link_stats(p);
|
||||
return link_stats_is_fresh(stats);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
rpl_set_preferred_parent(rpl_dag_t *dag, rpl_parent_t *p)
|
||||
{
|
||||
@ -640,20 +675,12 @@ rpl_add_parent(rpl_dag_t *dag, rpl_dio_t *dio, uip_ipaddr_t *addr)
|
||||
if(p == NULL) {
|
||||
PRINTF("RPL: rpl_add_parent p NULL\n");
|
||||
} else {
|
||||
uip_ds6_nbr_t *nbr;
|
||||
nbr = rpl_get_nbr(p);
|
||||
|
||||
p->dag = dag;
|
||||
p->rank = dio->rank;
|
||||
p->dtsn = dio->dtsn;
|
||||
|
||||
/* Check whether we have a neighbor that has not gotten a link metric yet */
|
||||
if(nbr != NULL && nbr->link_metric == 0) {
|
||||
nbr->link_metric = RPL_INIT_LINK_METRIC * RPL_DAG_MC_ETX_DIVISOR;
|
||||
}
|
||||
#if RPL_DAG_MC != RPL_DAG_MC_NONE
|
||||
#if RPL_WITH_MC
|
||||
memcpy(&p->mc, &dio->mc, sizeof(p->mc));
|
||||
#endif /* RPL_DAG_MC != RPL_DAG_MC_NONE */
|
||||
#endif /* RPL_WITH_MC */
|
||||
}
|
||||
}
|
||||
|
||||
@ -757,7 +784,7 @@ rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p)
|
||||
|
||||
instance->of->update_metric_container(instance);
|
||||
/* Update the DAG rank. */
|
||||
best_dag->rank = instance->of->calculate_rank(best_dag->preferred_parent, 0);
|
||||
best_dag->rank = rpl_rank_via_parent(best_dag->preferred_parent);
|
||||
if(last_parent == NULL || best_dag->rank < best_dag->min_rank) {
|
||||
best_dag->min_rank = best_dag->rank;
|
||||
} else if(!acceptable_rank(best_dag, best_dag->rank)) {
|
||||
@ -798,20 +825,35 @@ rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p)
|
||||
static rpl_parent_t *
|
||||
best_parent(rpl_dag_t *dag)
|
||||
{
|
||||
rpl_parent_t *p, *best;
|
||||
rpl_parent_t *p;
|
||||
rpl_of_t *of;
|
||||
rpl_parent_t *best = NULL;
|
||||
|
||||
best = NULL;
|
||||
if(dag == NULL || dag->instance == NULL || dag->instance->of == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = nbr_table_head(rpl_parents);
|
||||
while(p != NULL) {
|
||||
of = dag->instance->of;
|
||||
/* Search for the best parent according to the OF */
|
||||
for(p = nbr_table_head(rpl_parents); p != NULL; p = nbr_table_next(rpl_parents, p)) {
|
||||
|
||||
/* Exclude parents from other DAGs or announcing an infinite rank */
|
||||
if(p->dag != dag || p->rank == INFINITE_RANK) {
|
||||
/* ignore this neighbor */
|
||||
} else if(best == NULL) {
|
||||
best = p;
|
||||
} else {
|
||||
best = dag->instance->of->best_parent(best, p);
|
||||
continue;
|
||||
}
|
||||
p = nbr_table_next(rpl_parents, p);
|
||||
|
||||
#ifndef UIP_CONF_ND6_SEND_NA
|
||||
{
|
||||
uip_ds6_nbr_t *nbr = rpl_get_nbr(p);
|
||||
/* Exclude links to a neighbor that is not reachable at a NUD level */
|
||||
if(nbr == NULL || nbr->state != NBR_REACHABLE) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif /* UIP_CONF_ND6_SEND_NA */
|
||||
|
||||
/* Now we have an acceptable parent, check if it is the new best */
|
||||
best = of->best_parent(best, p);
|
||||
}
|
||||
|
||||
return best;
|
||||
@ -823,9 +865,12 @@ rpl_select_parent(rpl_dag_t *dag)
|
||||
rpl_parent_t *best = best_parent(dag);
|
||||
|
||||
if(best != NULL) {
|
||||
rpl_set_preferred_parent(dag, best);
|
||||
dag->rank = dag->instance->of->calculate_rank(dag->preferred_parent, 0);
|
||||
if(rpl_parent_is_fresh(best)) {
|
||||
rpl_set_preferred_parent(dag, best);
|
||||
dag->rank = rpl_rank_via_parent(dag->preferred_parent);
|
||||
}
|
||||
} else {
|
||||
rpl_set_preferred_parent(dag, best);
|
||||
dag->rank = INFINITE_RANK;
|
||||
}
|
||||
|
||||
@ -1003,6 +1048,10 @@ rpl_join_instance(uip_ipaddr_t *from, rpl_dio_t *dio)
|
||||
|
||||
instance->of = of;
|
||||
instance->mop = dio->mop;
|
||||
instance->mc.type = dio->mc.type;
|
||||
instance->mc.flags = dio->mc.flags;
|
||||
instance->mc.aggr = dio->mc.aggr;
|
||||
instance->mc.prec = dio->mc.prec;
|
||||
instance->current_dag = dag;
|
||||
instance->dtsn_out = RPL_LOLLIPOP_INIT;
|
||||
|
||||
@ -1022,7 +1071,7 @@ rpl_join_instance(uip_ipaddr_t *from, rpl_dio_t *dio)
|
||||
|
||||
rpl_set_preferred_parent(dag, p);
|
||||
instance->of->update_metric_container(instance);
|
||||
dag->rank = instance->of->calculate_rank(p, 0);
|
||||
dag->rank = rpl_rank_via_parent(p);
|
||||
/* So far this is the lowest rank we are aware of. */
|
||||
dag->min_rank = dag->rank;
|
||||
|
||||
@ -1045,6 +1094,8 @@ rpl_join_instance(uip_ipaddr_t *from, rpl_dio_t *dio)
|
||||
} else {
|
||||
PRINTF("RPL: The DIO does not meet the prerequisites for sending a DAO\n");
|
||||
}
|
||||
|
||||
instance->of->reset(dag);
|
||||
}
|
||||
|
||||
#if RPL_MAX_DAG_PER_INSTANCE > 1
|
||||
@ -1115,7 +1166,7 @@ rpl_add_dag(uip_ipaddr_t *from, rpl_dio_t *dio)
|
||||
memcpy(&dag->prefix_info, &dio->prefix_info, sizeof(rpl_prefix_t));
|
||||
|
||||
rpl_set_preferred_parent(dag, p);
|
||||
dag->rank = instance->of->calculate_rank(p, 0);
|
||||
dag->rank = rpl_rank_via_parent(p);
|
||||
dag->min_rank = dag->rank; /* So far this is the lowest rank we know of. */
|
||||
|
||||
PRINTF("RPL: Joined DAG with instance ID %u, rank %hu, DAG ID ",
|
||||
@ -1157,7 +1208,7 @@ global_repair(uip_ipaddr_t *from, rpl_dag_t *dag, rpl_dio_t *dio)
|
||||
PRINTF("RPL: Failed to add a parent during the global repair\n");
|
||||
dag->rank = INFINITE_RANK;
|
||||
} else {
|
||||
dag->rank = dag->instance->of->calculate_rank(p, 0);
|
||||
dag->rank = rpl_rank_via_parent(p);
|
||||
dag->min_rank = dag->rank;
|
||||
PRINTF("RPL: rpl_process_parent_event global repair\n");
|
||||
rpl_process_parent_event(dag->instance, p);
|
||||
@ -1446,14 +1497,14 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
|
||||
PRINT6ADDR(&instance->current_dag->dag_id);
|
||||
PRINTF(", rank %u, min_rank %u, ",
|
||||
instance->current_dag->rank, instance->current_dag->min_rank);
|
||||
PRINTF("parent rank %u, parent etx %u, link metric %u, instance etx %u\n",
|
||||
p->rank, -1/*p->mc.obj.etx*/, rpl_get_nbr(p)->link_metric, instance->mc.obj.etx);
|
||||
PRINTF("parent rank %u, link metric %u\n",
|
||||
p->rank, rpl_get_parent_link_metric(p));
|
||||
|
||||
/* We have allocated a candidate parent; process the DIO further. */
|
||||
|
||||
#if RPL_DAG_MC != RPL_DAG_MC_NONE
|
||||
#if RPL_WITH_MC
|
||||
memcpy(&p->mc, &dio->mc, sizeof(p->mc));
|
||||
#endif /* RPL_DAG_MC != RPL_DAG_MC_NONE */
|
||||
#endif /* RPL_WITH_MC */
|
||||
if(rpl_process_parent_event(instance, p) == 0) {
|
||||
PRINTF("RPL: The candidate parent is rejected\n");
|
||||
return;
|
||||
|
@ -32,7 +32,7 @@
|
||||
|
||||
/**
|
||||
* \file
|
||||
* The Minimum Rank with Hysteresis Objective Function (MRHOF)
|
||||
* The Minimum Rank with Hysteresis Objective Function (MRHOF), RFC6719
|
||||
*
|
||||
* This implementation uses the estimated number of
|
||||
* transmissions (ETX) as the additive routing metric,
|
||||
@ -46,83 +46,48 @@
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "net/rpl/rpl.h"
|
||||
#include "net/rpl/rpl-private.h"
|
||||
#include "net/nbr-table.h"
|
||||
#include "net/link-stats.h"
|
||||
|
||||
#define DEBUG DEBUG_NONE
|
||||
#include "net/ip/uip-debug.h"
|
||||
|
||||
static void reset(rpl_dag_t *);
|
||||
static void neighbor_link_callback(rpl_parent_t *, int, int);
|
||||
#if RPL_WITH_DAO_ACK
|
||||
static void dao_ack_callback(rpl_parent_t *, int);
|
||||
#endif
|
||||
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);
|
||||
static void update_metric_container(rpl_instance_t *);
|
||||
|
||||
rpl_of_t rpl_mrhof = {
|
||||
reset,
|
||||
neighbor_link_callback,
|
||||
#if RPL_WITH_DAO_ACK
|
||||
dao_ack_callback,
|
||||
#endif
|
||||
best_parent,
|
||||
best_dag,
|
||||
calculate_rank,
|
||||
update_metric_container,
|
||||
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
|
||||
/* RFC6551 and RFC6719 do not mandate the use of a specific formula to
|
||||
* compute the ETX value. This MRHOF implementation relies on the value
|
||||
* computed by the link-stats module. It has an optional feature,
|
||||
* RPL_MRHOF_CONF_SQUARED_ETX, that consists in squaring this value.
|
||||
* This basically penalizes bad links while preserving the semantics of ETX
|
||||
* (1 = perfect link, more = worse link). As a result, MRHOF will favor
|
||||
* good links over short paths. Recommended when reliability is a priority.
|
||||
* Without this feature, a hop with 50% PRR (ETX=2) is equivalent to two
|
||||
* perfect hops with 100% PRR (ETX=1+1=2). With this feature, the former
|
||||
* path obtains ETX=2*2=4 and the former ETX=1*1+1*1=2. */
|
||||
#ifdef RPL_MRHOF_CONF_SQUARED_ETX
|
||||
#define RPL_MRHOF_SQUARED_ETX RPL_MRHOF_CONF_SQUARED_ETX
|
||||
#else /* RPL_MRHOF_CONF_SQUARED_ETX */
|
||||
#define RPL_MRHOF_SQUARED_ETX 0
|
||||
#endif /* RPL_MRHOF_CONF_SQUARED_ETX */
|
||||
|
||||
/* Configuration parameters of RFC6719. Reject parents that have a higher
|
||||
* link metric than the following. We use the default values from the RFC. */
|
||||
#define MAX_LINK_METRIC 512 /* Eq ETX of 4 */
|
||||
/* Reject parents that have a higher path cost than the following. */
|
||||
#define MAX_PATH_COST 100
|
||||
|
||||
/*
|
||||
* The rank must differ more than 1/PARENT_SWITCH_THRESHOLD_DIV in order
|
||||
* to switch preferred parent.
|
||||
#define MAX_PATH_COST 32768 /* Eq path ETX of 256 */
|
||||
/* Hysteresis of MRHOF: the rank must differ more than PARENT_SWITCH_THRESHOLD_DIV
|
||||
* in order to switch preferred parent. Default in RFC6719: 192, eq ETX of 1.5.
|
||||
* We use a more aggressive setting: 96, eq ETX of 0.75.
|
||||
*/
|
||||
#define PARENT_SWITCH_THRESHOLD_DIV 2
|
||||
|
||||
typedef uint16_t rpl_path_metric_t;
|
||||
|
||||
static rpl_path_metric_t
|
||||
calculate_path_metric(rpl_parent_t *p)
|
||||
{
|
||||
uip_ds6_nbr_t *nbr;
|
||||
if(p == NULL) {
|
||||
return MAX_PATH_COST * RPL_DAG_MC_ETX_DIVISOR;
|
||||
}
|
||||
nbr = rpl_get_nbr(p);
|
||||
if(nbr == NULL) {
|
||||
return MAX_PATH_COST * RPL_DAG_MC_ETX_DIVISOR;
|
||||
}
|
||||
#if RPL_DAG_MC == RPL_DAG_MC_NONE
|
||||
{
|
||||
return p->rank + (uint16_t)nbr->link_metric;
|
||||
}
|
||||
#elif RPL_DAG_MC == RPL_DAG_MC_ETX
|
||||
return p->mc.obj.etx + (uint16_t)nbr->link_metric;
|
||||
#elif RPL_DAG_MC == RPL_DAG_MC_ENERGY
|
||||
return p->mc.obj.energy.energy_est + (uint16_t)nbr->link_metric;
|
||||
#else
|
||||
#error "Unsupported RPL_DAG_MC configured. See rpl.h."
|
||||
#endif /* RPL_DAG_MC */
|
||||
}
|
||||
#define PARENT_SWITCH_THRESHOLD 96
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
reset(rpl_dag_t *dag)
|
||||
{
|
||||
PRINTF("RPL: Reset MRHOF\n");
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#if RPL_WITH_DAO_ACK
|
||||
static void
|
||||
dao_ack_callback(rpl_parent_t *p, int status)
|
||||
@ -141,80 +106,117 @@ dao_ack_callback(rpl_parent_t *p, int status)
|
||||
}
|
||||
}
|
||||
#endif /* RPL_WITH_DAO_ACK */
|
||||
|
||||
static void
|
||||
neighbor_link_callback(rpl_parent_t *p, int status, int numtx)
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static uint16_t
|
||||
parent_link_metric(rpl_parent_t *p)
|
||||
{
|
||||
uint16_t recorded_etx = 0;
|
||||
uint16_t packet_etx = numtx * RPL_DAG_MC_ETX_DIVISOR;
|
||||
uint16_t new_etx;
|
||||
uip_ds6_nbr_t *nbr = NULL;
|
||||
|
||||
nbr = rpl_get_nbr(p);
|
||||
if(nbr == NULL) {
|
||||
/* No neighbor for this parent - something bad has occurred */
|
||||
return;
|
||||
}
|
||||
|
||||
recorded_etx = nbr->link_metric;
|
||||
|
||||
/* Do not penalize the ETX when collisions or transmission errors occur. */
|
||||
if(status == MAC_TX_OK || status == MAC_TX_NOACK) {
|
||||
if(status == MAC_TX_NOACK) {
|
||||
packet_etx = MAX_LINK_METRIC * RPL_DAG_MC_ETX_DIVISOR;
|
||||
}
|
||||
|
||||
if(p->flags & RPL_PARENT_FLAG_LINK_METRIC_VALID) {
|
||||
/* We already have a valid link metric, use weighted moving average to update it */
|
||||
new_etx = ((uint32_t)recorded_etx * ETX_ALPHA +
|
||||
(uint32_t)packet_etx * (ETX_SCALE - ETX_ALPHA)) / ETX_SCALE;
|
||||
} else {
|
||||
/* We don't have a valid link metric, set it to the current packet's ETX */
|
||||
new_etx = packet_etx;
|
||||
/* Set link metric as valid */
|
||||
p->flags |= RPL_PARENT_FLAG_LINK_METRIC_VALID;
|
||||
}
|
||||
|
||||
PRINTF("RPL: ETX changed from %u to %u (packet ETX = %u)\n",
|
||||
(unsigned)(recorded_etx / RPL_DAG_MC_ETX_DIVISOR),
|
||||
(unsigned)(new_etx / RPL_DAG_MC_ETX_DIVISOR),
|
||||
(unsigned)(packet_etx / RPL_DAG_MC_ETX_DIVISOR));
|
||||
/* update the link metric for this nbr */
|
||||
nbr->link_metric = new_etx;
|
||||
const struct link_stats *stats = rpl_get_parent_link_stats(p);
|
||||
if(stats != NULL) {
|
||||
#if RPL_MRHOF_SQUARED_ETX
|
||||
uint32_t squared_etx = ((uint32_t)stats->etx * stats->etx) / LINK_STATS_ETX_DIVISOR;
|
||||
return (uint16_t)MIN(squared_etx, 0xffff);
|
||||
#else /* RPL_MRHOF_SQUARED_ETX */
|
||||
return stats->etx;
|
||||
#endif /* RPL_MRHOF_SQUARED_ETX */
|
||||
}
|
||||
return 0xffff;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static uint16_t
|
||||
parent_path_cost(rpl_parent_t *p)
|
||||
{
|
||||
uint16_t base;
|
||||
|
||||
if(p == NULL || p->dag == NULL || p->dag->instance == NULL) {
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
#if RPL_WITH_MC
|
||||
/* Handle the different MC types */
|
||||
switch(p->dag->instance->mc.type) {
|
||||
case RPL_DAG_MC_ETX:
|
||||
base = p->mc.obj.etx;
|
||||
break;
|
||||
case RPL_DAG_MC_ENERGY:
|
||||
base = p->mc.obj.energy.energy_est << 8;
|
||||
break;
|
||||
default:
|
||||
base = p->rank;
|
||||
break;
|
||||
}
|
||||
#else /* RPL_WITH_MC */
|
||||
base = p->rank;
|
||||
#endif /* RPL_WITH_MC */
|
||||
|
||||
/* path cost upper bound: 0xffff */
|
||||
return MIN((uint32_t)base + parent_link_metric(p), 0xffff);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static rpl_rank_t
|
||||
calculate_rank(rpl_parent_t *p, rpl_rank_t base_rank)
|
||||
rank_via_parent(rpl_parent_t *p)
|
||||
{
|
||||
rpl_rank_t new_rank;
|
||||
rpl_rank_t rank_increase;
|
||||
uip_ds6_nbr_t *nbr;
|
||||
uint16_t min_hoprankinc;
|
||||
uint16_t path_cost;
|
||||
|
||||
if(p == NULL || (nbr = rpl_get_nbr(p)) == NULL) {
|
||||
if(base_rank == 0) {
|
||||
return INFINITE_RANK;
|
||||
}
|
||||
rank_increase = RPL_INIT_LINK_METRIC * RPL_DAG_MC_ETX_DIVISOR;
|
||||
} else {
|
||||
rank_increase = nbr->link_metric;
|
||||
if(base_rank == 0) {
|
||||
base_rank = p->rank;
|
||||
}
|
||||
if(p == NULL || p->dag == NULL || p->dag->instance == NULL) {
|
||||
return INFINITE_RANK;
|
||||
}
|
||||
|
||||
if(INFINITE_RANK - base_rank < rank_increase) {
|
||||
/* Reached the maximum rank. */
|
||||
new_rank = INFINITE_RANK;
|
||||
} else {
|
||||
/* Calculate the rank based on the new rank information from DIO or
|
||||
stored otherwise. */
|
||||
new_rank = base_rank + rank_increase;
|
||||
}
|
||||
min_hoprankinc = p->dag->instance->min_hoprankinc;
|
||||
path_cost = parent_path_cost(p);
|
||||
|
||||
return new_rank;
|
||||
/* Rank lower-bound: parent rank + min_hoprankinc */
|
||||
return MAX(MIN((uint32_t)p->rank + min_hoprankinc, 0xffff), path_cost);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int
|
||||
parent_is_acceptable(rpl_parent_t *p)
|
||||
{
|
||||
uint16_t link_metric = parent_link_metric(p);
|
||||
uint16_t path_cost = parent_path_cost(p);
|
||||
/* Exclude links with too high link metrics or path cost (RFC6719, 3.2.2) */
|
||||
return link_metric <= MAX_LINK_METRIC && path_cost <= MAX_PATH_COST;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static rpl_parent_t *
|
||||
best_parent(rpl_parent_t *p1, rpl_parent_t *p2)
|
||||
{
|
||||
rpl_dag_t *dag;
|
||||
uint16_t p1_cost;
|
||||
uint16_t p2_cost;
|
||||
int p1_is_acceptable;
|
||||
int p2_is_acceptable;
|
||||
|
||||
if(p1 == NULL || p2 == NULL) {
|
||||
/* Return non-null parent if any */
|
||||
return p1 == NULL ? p2 : p1;
|
||||
}
|
||||
|
||||
p1_is_acceptable = parent_is_acceptable(p1);
|
||||
p2_is_acceptable = parent_is_acceptable(p2);
|
||||
/* Is only one parent is acceptable, select it. If both are acceptable, or
|
||||
* both non-acceptable, proceed to traditional parent comparison. This is a
|
||||
* slight departure from the standard but allows to keep connectivity even
|
||||
* all neighbors appear to have a bad link. */
|
||||
if(p1_is_acceptable != p2_is_acceptable) {
|
||||
return p1_is_acceptable ? p1 : p2;
|
||||
}
|
||||
|
||||
dag = p1->dag; /* Both parents are in the same DAG. */
|
||||
p1_cost = parent_path_cost(p1);
|
||||
p2_cost = parent_path_cost(p2);
|
||||
|
||||
/* Maintain stability of the preferred parent in case of similar ranks. */
|
||||
if(p1 == dag->preferred_parent || p2 == dag->preferred_parent) {
|
||||
if(p1_cost < p2_cost + PARENT_SWITCH_THRESHOLD &&
|
||||
p1_cost > p2_cost - PARENT_SWITCH_THRESHOLD) {
|
||||
return dag->preferred_parent;
|
||||
}
|
||||
}
|
||||
|
||||
return p1_cost < p2_cost ? p1 : p2;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static rpl_dag_t *
|
||||
best_dag(rpl_dag_t *d1, rpl_dag_t *d2)
|
||||
{
|
||||
@ -228,93 +230,76 @@ best_dag(rpl_dag_t *d1, rpl_dag_t *d2)
|
||||
|
||||
return d1->rank < d2->rank ? d1 : d2;
|
||||
}
|
||||
|
||||
static rpl_parent_t *
|
||||
best_parent(rpl_parent_t *p1, rpl_parent_t *p2)
|
||||
{
|
||||
rpl_dag_t *dag;
|
||||
rpl_path_metric_t min_diff;
|
||||
rpl_path_metric_t p1_metric;
|
||||
rpl_path_metric_t p2_metric;
|
||||
|
||||
dag = p1->dag; /* Both parents are in the same DAG. */
|
||||
|
||||
min_diff = RPL_DAG_MC_ETX_DIVISOR /
|
||||
PARENT_SWITCH_THRESHOLD_DIV;
|
||||
|
||||
p1_metric = calculate_path_metric(p1);
|
||||
p2_metric = calculate_path_metric(p2);
|
||||
|
||||
/* Maintain stability of the preferred parent in case of similar ranks. */
|
||||
if(p1 == dag->preferred_parent || p2 == dag->preferred_parent) {
|
||||
if(p1_metric < p2_metric + min_diff &&
|
||||
p1_metric > p2_metric - min_diff) {
|
||||
PRINTF("RPL: MRHOF hysteresis: %u <= %u <= %u\n",
|
||||
p2_metric - min_diff,
|
||||
p1_metric,
|
||||
p2_metric + min_diff);
|
||||
return dag->preferred_parent;
|
||||
}
|
||||
}
|
||||
|
||||
return p1_metric < p2_metric ? p1 : p2;
|
||||
}
|
||||
|
||||
#if RPL_DAG_MC == RPL_DAG_MC_NONE
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#if !RPL_WITH_MC
|
||||
static void
|
||||
update_metric_container(rpl_instance_t *instance)
|
||||
{
|
||||
instance->mc.type = RPL_DAG_MC;
|
||||
instance->mc.type = RPL_DAG_MC_NONE;
|
||||
}
|
||||
#else
|
||||
#else /* RPL_WITH_MC */
|
||||
static void
|
||||
update_metric_container(rpl_instance_t *instance)
|
||||
{
|
||||
rpl_path_metric_t path_metric;
|
||||
rpl_dag_t *dag;
|
||||
#if RPL_DAG_MC == RPL_DAG_MC_ENERGY
|
||||
uint16_t path_cost;
|
||||
uint8_t type;
|
||||
#endif
|
||||
|
||||
instance->mc.type = RPL_DAG_MC;
|
||||
instance->mc.flags = RPL_DAG_MC_FLAG_P;
|
||||
instance->mc.aggr = RPL_DAG_MC_AGGR_ADDITIVE;
|
||||
instance->mc.prec = 0;
|
||||
|
||||
dag = instance->current_dag;
|
||||
|
||||
if (!dag->joined) {
|
||||
if(dag == NULL || !dag->joined) {
|
||||
PRINTF("RPL: Cannot update the metric container when not joined\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(dag->rank == ROOT_RANK(instance)) {
|
||||
path_metric = 0;
|
||||
/* Configure MC at root only, other nodes are auto-configured when joining */
|
||||
instance->mc.type = RPL_DAG_MC;
|
||||
instance->mc.flags = 0;
|
||||
instance->mc.aggr = RPL_DAG_MC_AGGR_ADDITIVE;
|
||||
instance->mc.prec = 0;
|
||||
path_cost = dag->rank;
|
||||
} else {
|
||||
path_metric = calculate_path_metric(dag->preferred_parent);
|
||||
path_cost = parent_path_cost(dag->preferred_parent);
|
||||
}
|
||||
|
||||
#if RPL_DAG_MC == RPL_DAG_MC_ETX
|
||||
instance->mc.length = sizeof(instance->mc.obj.etx);
|
||||
instance->mc.obj.etx = path_metric;
|
||||
|
||||
PRINTF("RPL: My path ETX to the root is %u.%u\n",
|
||||
instance->mc.obj.etx / RPL_DAG_MC_ETX_DIVISOR,
|
||||
(instance->mc.obj.etx % RPL_DAG_MC_ETX_DIVISOR * 100) /
|
||||
RPL_DAG_MC_ETX_DIVISOR);
|
||||
#elif RPL_DAG_MC == RPL_DAG_MC_ENERGY
|
||||
instance->mc.length = sizeof(instance->mc.obj.energy);
|
||||
|
||||
if(dag->rank == ROOT_RANK(instance)) {
|
||||
type = RPL_DAG_MC_ENERGY_TYPE_MAINS;
|
||||
} else {
|
||||
type = RPL_DAG_MC_ENERGY_TYPE_BATTERY;
|
||||
/* Handle the different MC types */
|
||||
switch(instance->mc.type) {
|
||||
case RPL_DAG_MC_NONE:
|
||||
break;
|
||||
case RPL_DAG_MC_ETX:
|
||||
instance->mc.length = sizeof(instance->mc.obj.etx);
|
||||
instance->mc.obj.etx = path_cost;
|
||||
break;
|
||||
case RPL_DAG_MC_ENERGY:
|
||||
instance->mc.length = sizeof(instance->mc.obj.energy);
|
||||
if(dag->rank == ROOT_RANK(instance)) {
|
||||
type = RPL_DAG_MC_ENERGY_TYPE_MAINS;
|
||||
} else {
|
||||
type = RPL_DAG_MC_ENERGY_TYPE_BATTERY;
|
||||
}
|
||||
instance->mc.obj.energy.flags = type << RPL_DAG_MC_ENERGY_TYPE;
|
||||
/* Energy_est is only one byte, use the least significant byte of the path metric. */
|
||||
instance->mc.obj.energy.energy_est = path_cost >> 8;
|
||||
break;
|
||||
default:
|
||||
PRINTF("RPL: MRHOF, non-supported MC %u\n", instance->mc.type);
|
||||
break;
|
||||
}
|
||||
|
||||
instance->mc.obj.energy.flags = type << RPL_DAG_MC_ENERGY_TYPE;
|
||||
instance->mc.obj.energy.energy_est = path_metric;
|
||||
#endif /* RPL_DAG_MC == RPL_DAG_MC_ETX */
|
||||
}
|
||||
#endif /* RPL_DAG_MC == RPL_DAG_MC_NONE */
|
||||
#endif /* RPL_WITH_MC */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
rpl_of_t rpl_mrhof = {
|
||||
reset,
|
||||
#if RPL_WITH_DAO_ACK
|
||||
dao_ack_callback,
|
||||
#endif
|
||||
parent_link_metric,
|
||||
parent_path_cost,
|
||||
rank_via_parent,
|
||||
best_parent,
|
||||
best_dag,
|
||||
update_metric_container,
|
||||
RPL_OCP_MRHOF
|
||||
};
|
||||
|
||||
/** @}*/
|
||||
|
@ -27,11 +27,12 @@
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* An implementation of RPL's objective function 0.
|
||||
* An implementation of RPL's objective function 0, RFC6552
|
||||
*
|
||||
* \author Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes <nvt@sics.se>
|
||||
*/
|
||||
@ -41,136 +42,176 @@
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "net/rpl/rpl.h"
|
||||
#include "net/rpl/rpl-private.h"
|
||||
#include "net/nbr-table.h"
|
||||
#include "net/link-stats.h"
|
||||
|
||||
#define DEBUG DEBUG_NONE
|
||||
#include "net/ip/uip-debug.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 *);
|
||||
static rpl_rank_t calculate_rank(rpl_parent_t *, rpl_rank_t);
|
||||
static void update_metric_container(rpl_instance_t *);
|
||||
/* Constants from RFC6552. We use the default values. */
|
||||
#define RANK_STRETCH 0 /* Must be in the range [0;5] */
|
||||
#define RANK_FACTOR 1 /* Must be in the range [1;4] */
|
||||
|
||||
rpl_of_t rpl_of0 = {
|
||||
reset,
|
||||
NULL,
|
||||
#if RPL_WITH_DAO_ACK
|
||||
NULL,
|
||||
#endif
|
||||
best_parent,
|
||||
best_dag,
|
||||
calculate_rank,
|
||||
update_metric_container,
|
||||
0
|
||||
};
|
||||
#define MIN_STEP_OF_RANK 1
|
||||
#define MAX_STEP_OF_RANK 9
|
||||
|
||||
#define DEFAULT_RANK_INCREMENT RPL_MIN_HOPRANKINC
|
||||
/* OF0 computes rank increase as follows:
|
||||
* rank_increase = (RANK_FACTOR * STEP_OF_RANK + RANK_STRETCH) * min_hop_rank_increase
|
||||
* STEP_OF_RANK is an implementation-specific scalar value in the range [1;9].
|
||||
* RFC6552 provides a default value of 3 but recommends to use a dynamic link metric
|
||||
* such as ETX.
|
||||
* */
|
||||
|
||||
#define MIN_DIFFERENCE (RPL_MIN_HOPRANKINC + RPL_MIN_HOPRANKINC / 2)
|
||||
#define RPL_OF0_FIXED_SR 0
|
||||
#define RPL_OF0_ETX_BASED_SR 1
|
||||
/* Select RPL_OF0_FIXED_SR or RPL_OF0_ETX_BASED_SR */
|
||||
#ifdef RPL_OF0_CONF_SR
|
||||
#define RPL_OF0_SR RPL_OF0_CONF_SR
|
||||
#else /* RPL_OF0_CONF_SR */
|
||||
#define RPL_OF0_SR RPL_OF0_ETX_BASED_SR
|
||||
#endif /* RPL_OF0_CONF_SR */
|
||||
|
||||
#if RPL_OF0_FIXED_SR
|
||||
#define STEP_OF_RANK(p) (3)
|
||||
#endif /* RPL_OF0_FIXED_SR */
|
||||
|
||||
#if RPL_OF0_ETX_BASED_SR
|
||||
/* Numbers suggested by P. Thubert for in the 6TiSCH WG. Anything that maps ETX to
|
||||
* a step between 1 and 9 works. */
|
||||
#define STEP_OF_RANK(p) (((3 * parent_link_metric(p)) / LINK_STATS_ETX_DIVISOR) - 2)
|
||||
#endif /* RPL_OF0_ETX_BASED_SR */
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
reset(rpl_dag_t *dag)
|
||||
{
|
||||
PRINTF("RPL: Resetting OF0\n");
|
||||
PRINTF("RPL: Reset OF0\n");
|
||||
}
|
||||
|
||||
static rpl_rank_t
|
||||
calculate_rank(rpl_parent_t *p, rpl_rank_t base_rank)
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static uint16_t
|
||||
parent_link_metric(rpl_parent_t *p)
|
||||
{
|
||||
rpl_rank_t increment;
|
||||
if(base_rank == 0) {
|
||||
if(p == NULL) {
|
||||
return INFINITE_RANK;
|
||||
}
|
||||
base_rank = p->rank;
|
||||
}
|
||||
|
||||
increment = p != NULL ?
|
||||
p->dag->instance->min_hoprankinc :
|
||||
DEFAULT_RANK_INCREMENT;
|
||||
|
||||
if((rpl_rank_t)(base_rank + increment) < base_rank) {
|
||||
PRINTF("RPL: OF0 rank %d incremented to infinite rank due to wrapping\n",
|
||||
base_rank);
|
||||
/* OF0 operates without metric container; the only metric we have is ETX */
|
||||
const struct link_stats *stats = rpl_get_parent_link_stats(p);
|
||||
return stats != NULL ? stats->etx : 0xffff;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static uint16_t
|
||||
parent_rank_increase(rpl_parent_t *p)
|
||||
{
|
||||
uint16_t min_hoprankinc;
|
||||
if(p == NULL || p->dag == NULL || p->dag->instance == NULL) {
|
||||
return INFINITE_RANK;
|
||||
}
|
||||
return base_rank + increment;
|
||||
|
||||
min_hoprankinc = p->dag->instance->min_hoprankinc;
|
||||
return (RANK_FACTOR * STEP_OF_RANK(p) + RANK_STRETCH) * min_hoprankinc;
|
||||
}
|
||||
|
||||
static rpl_dag_t *
|
||||
best_dag(rpl_dag_t *d1, rpl_dag_t *d2)
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static uint16_t
|
||||
parent_path_cost(rpl_parent_t *p)
|
||||
{
|
||||
if(d1->grounded) {
|
||||
if (!d2->grounded) {
|
||||
return d1;
|
||||
}
|
||||
} else if(d2->grounded) {
|
||||
return d2;
|
||||
if(p == NULL) {
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
if(d1->preference < d2->preference) {
|
||||
return d2;
|
||||
/* path cost upper bound: 0xffff */
|
||||
return MIN((uint32_t)p->rank + parent_link_metric(p), 0xffff);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static rpl_rank_t
|
||||
rank_via_parent(rpl_parent_t *p)
|
||||
{
|
||||
if(p == NULL) {
|
||||
return INFINITE_RANK;
|
||||
} else {
|
||||
if(d1->preference > d2->preference) {
|
||||
return d1;
|
||||
}
|
||||
}
|
||||
|
||||
if(d2->rank < d1->rank) {
|
||||
return d2;
|
||||
} else {
|
||||
return d1;
|
||||
return MIN((uint32_t)p->rank + parent_rank_increase(p), INFINITE_RANK);
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int
|
||||
parent_is_acceptable(rpl_parent_t *p)
|
||||
{
|
||||
return STEP_OF_RANK(p) >= MIN_STEP_OF_RANK
|
||||
&& STEP_OF_RANK(p) <= MAX_STEP_OF_RANK;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static rpl_parent_t *
|
||||
best_parent(rpl_parent_t *p1, rpl_parent_t *p2)
|
||||
{
|
||||
rpl_rank_t r1, r2;
|
||||
rpl_dag_t *dag;
|
||||
uip_ds6_nbr_t *nbr1, *nbr2;
|
||||
nbr1 = rpl_get_nbr(p1);
|
||||
nbr2 = rpl_get_nbr(p2);
|
||||
rpl_dag_t *dag;
|
||||
uint16_t p1_cost;
|
||||
uint16_t p2_cost;
|
||||
int p1_is_acceptable;
|
||||
int p2_is_acceptable;
|
||||
|
||||
dag = (rpl_dag_t *)p1->dag; /* Both parents must be in the same DAG. */
|
||||
|
||||
if(nbr1 == NULL || nbr2 == NULL) {
|
||||
return dag->preferred_parent;
|
||||
if(p1 == NULL || p2 == NULL) {
|
||||
/* Return non-null parent if any */
|
||||
return p1 == NULL ? p2 : p1;
|
||||
}
|
||||
|
||||
PRINTF("RPL: Comparing parent ");
|
||||
PRINT6ADDR(rpl_get_parent_ipaddr(p1));
|
||||
PRINTF(" (confidence %d, rank %d) with parent ",
|
||||
nbr1->link_metric, p1->rank);
|
||||
PRINT6ADDR(rpl_get_parent_ipaddr(p2));
|
||||
PRINTF(" (confidence %d, rank %d)\n",
|
||||
nbr2->link_metric, p2->rank);
|
||||
p1_is_acceptable = parent_is_acceptable(p1);
|
||||
p2_is_acceptable = parent_is_acceptable(p2);
|
||||
/* Is only one parent is acceptable, select it. If both are acceptable, or
|
||||
* both non-acceptable, proceed to traditional parent comparison. This is a
|
||||
* slight departure from the standard but allows to keep connectivity even
|
||||
* all neighbors appear to have a bad link. */
|
||||
if(p1_is_acceptable != p2_is_acceptable) {
|
||||
return p1_is_acceptable ? p1 : p2;
|
||||
}
|
||||
|
||||
dag = p1->dag; /* Both parents are in the same DAG. */
|
||||
p1_cost = parent_path_cost(p1);
|
||||
p2_cost = parent_path_cost(p2);
|
||||
|
||||
r1 = DAG_RANK(p1->rank, p1->dag->instance) * RPL_MIN_HOPRANKINC +
|
||||
nbr1->link_metric;
|
||||
r2 = DAG_RANK(p2->rank, p1->dag->instance) * RPL_MIN_HOPRANKINC +
|
||||
nbr2->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
|
||||
favourable combination. */
|
||||
|
||||
if(r1 < r2 + MIN_DIFFERENCE &&
|
||||
r1 > r2 - MIN_DIFFERENCE) {
|
||||
return dag->preferred_parent;
|
||||
} else if(r1 < r2) {
|
||||
return p1;
|
||||
/* Paths costs coarse-grained (multiple of min_hoprankinc), we operate without hysteresis */
|
||||
if(p1_cost != p2_cost) {
|
||||
/* Pick parent with lowest path cost */
|
||||
return p1_cost < p2_cost ? p1 : p2;
|
||||
} else {
|
||||
return p2;
|
||||
/* We have a tie! */
|
||||
/* Stik to current preferred parent if possible */
|
||||
if(p1 == dag->preferred_parent || p2 == dag->preferred_parent) {
|
||||
return dag->preferred_parent;
|
||||
}
|
||||
/* None of the nodes is the current preferred parent,
|
||||
* choose parent with best link metric */
|
||||
return parent_link_metric(p1) < parent_link_metric(p2) ? p1 : p2;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static rpl_dag_t *
|
||||
best_dag(rpl_dag_t *d1, rpl_dag_t *d2)
|
||||
{
|
||||
if(d1->grounded != d2->grounded) {
|
||||
return d1->grounded ? d1 : d2;
|
||||
}
|
||||
|
||||
if(d1->preference != d2->preference) {
|
||||
return d1->preference > d2->preference ? d1 : d2;
|
||||
}
|
||||
|
||||
return d1->rank < d2->rank ? d1 : d2;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
update_metric_container(rpl_instance_t *instance)
|
||||
{
|
||||
instance->mc.type = RPL_DAG_MC_NONE;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
rpl_of_t rpl_of0 = {
|
||||
reset,
|
||||
#if RPL_WITH_DAO_ACK
|
||||
NULL,
|
||||
#endif
|
||||
parent_link_metric,
|
||||
parent_path_cost,
|
||||
rank_via_parent,
|
||||
best_parent,
|
||||
best_dag,
|
||||
update_metric_container,
|
||||
RPL_OCP_OF0
|
||||
};
|
||||
|
||||
/** @}*/
|
||||
|
@ -199,13 +199,6 @@
|
||||
#define RPL_MCAST_LIFETIME 3
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The ETX in the metric container is expressed as a fixed-point value
|
||||
* whose integer part can be obtained by dividing the value by
|
||||
* RPL_DAG_MC_ETX_DIVISOR.
|
||||
*/
|
||||
#define RPL_DAG_MC_ETX_DIVISOR 256
|
||||
|
||||
/* DIS related */
|
||||
#define RPL_DIS_SEND 1
|
||||
|
||||
|
@ -43,6 +43,7 @@
|
||||
|
||||
#include "contiki-conf.h"
|
||||
#include "net/rpl/rpl-private.h"
|
||||
#include "net/link-stats.h"
|
||||
#include "net/ipv6/multicast/uip-mcast6.h"
|
||||
#include "lib/random.h"
|
||||
#include "sys/ctimer.h"
|
||||
|
@ -268,10 +268,6 @@ rpl_link_neighbor_callback(const linkaddr_t *addr, int status, int numtx)
|
||||
/* Trigger DAG rank recalculation. */
|
||||
PRINTF("RPL: rpl_link_neighbor_callback triggering update\n");
|
||||
parent->flags |= RPL_PARENT_FLAG_UPDATED;
|
||||
if(instance->of->neighbor_link_callback != NULL) {
|
||||
instance->of->neighbor_link_callback(parent, status, numtx);
|
||||
parent->last_tx_time = clock_time();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -350,8 +346,6 @@ rpl_init(void)
|
||||
#if RPL_CONF_STATS
|
||||
memset(&rpl_stats, 0, sizeof(rpl_stats));
|
||||
#endif
|
||||
|
||||
RPL_OF.reset(NULL);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
|
@ -113,11 +113,10 @@ struct rpl_dag;
|
||||
|
||||
struct rpl_parent {
|
||||
struct rpl_dag *dag;
|
||||
#if RPL_DAG_MC != RPL_DAG_MC_NONE
|
||||
#if RPL_WITH_MC
|
||||
rpl_metric_container_t mc;
|
||||
#endif /* RPL_DAG_MC != RPL_DAG_MC_NONE */
|
||||
#endif /* RPL_WITH_MC */
|
||||
rpl_rank_t rank;
|
||||
clock_time_t last_tx_time;
|
||||
uint8_t dtsn;
|
||||
uint8_t flags;
|
||||
};
|
||||
@ -159,11 +158,21 @@ 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.
|
||||
*
|
||||
* neighbor_link_callback(parent, known, etx)
|
||||
* parent_link_metric(parent)
|
||||
*
|
||||
* Receives link-layer neighbor information. The parameter "known" is set
|
||||
* either to 0 or 1. The "etx" parameter specifies the current
|
||||
* ETX(estimated transmissions) for the neighbor.
|
||||
* Returns the link metric of a parent
|
||||
*
|
||||
* parent_path_cost(parent)
|
||||
*
|
||||
* Returns the path cost of a parent
|
||||
*
|
||||
* rank_via_parent(parent)
|
||||
*
|
||||
* Returns our rank if we select a given parent as preferred parent
|
||||
*
|
||||
* parent_is_acceptable
|
||||
*
|
||||
* Returns 1 if a parent is usable as preferred parent, 0 otherwise
|
||||
*
|
||||
* best_parent(parent1, parent2)
|
||||
*
|
||||
@ -173,13 +182,6 @@ typedef struct rpl_instance rpl_instance_t;
|
||||
*
|
||||
* Compares two DAGs and returns the best one, according to the OF.
|
||||
*
|
||||
* calculate_rank(parent, base_rank)
|
||||
*
|
||||
* Calculates a rank value using the parent rank and a base rank.
|
||||
* If "parent" is NULL, the objective function selects a default increment
|
||||
* that is adds to the "base_rank". Otherwise, the OF uses information known
|
||||
* about "parent" to select an increment to the "base_rank".
|
||||
*
|
||||
* update_metric_container(dag)
|
||||
*
|
||||
* Updates the metric container for outgoing DIOs in a certain DAG.
|
||||
@ -194,20 +196,19 @@ typedef struct rpl_instance rpl_instance_t;
|
||||
*/
|
||||
struct rpl_of {
|
||||
void (*reset)(struct rpl_dag *);
|
||||
void (*neighbor_link_callback)(rpl_parent_t *, int, int);
|
||||
#if RPL_WITH_DAO_ACK
|
||||
void (*dao_ack_callback)(rpl_parent_t *, int status);
|
||||
#endif
|
||||
uint16_t (*parent_link_metric)(rpl_parent_t *);
|
||||
uint16_t (*parent_path_cost)(rpl_parent_t *);
|
||||
rpl_rank_t (*rank_via_parent)(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_rank_t (*calculate_rank)(rpl_parent_t *, rpl_rank_t);
|
||||
void (*update_metric_container)( rpl_instance_t *);
|
||||
rpl_ocp_t ocp;
|
||||
};
|
||||
typedef struct rpl_of rpl_of_t;
|
||||
|
||||
/* Declare the selected objective function. */
|
||||
extern rpl_of_t RPL_OF;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Instance */
|
||||
struct rpl_instance {
|
||||
@ -272,10 +273,14 @@ int rpl_verify_header(int);
|
||||
void rpl_insert_header(void);
|
||||
void rpl_remove_header(void);
|
||||
uint8_t rpl_invert_header(void);
|
||||
const struct link_stats *rpl_get_parent_link_stats(rpl_parent_t *p);
|
||||
int rpl_parent_is_fresh(rpl_parent_t *p);
|
||||
uint16_t rpl_get_parent_link_metric(rpl_parent_t *p);
|
||||
rpl_rank_t rpl_rank_via_parent(rpl_parent_t *p);
|
||||
const linkaddr_t *rpl_get_parent_lladdr(rpl_parent_t *p);
|
||||
uip_ipaddr_t *rpl_get_parent_ipaddr(rpl_parent_t *nbr);
|
||||
rpl_parent_t *rpl_get_parent(uip_lladdr_t *addr);
|
||||
rpl_rank_t rpl_get_parent_rank(uip_lladdr_t *addr);
|
||||
uint16_t rpl_get_parent_link_metric(const uip_lladdr_t *addr);
|
||||
void rpl_dag_init(void);
|
||||
uip_ds6_nbr_t *rpl_get_nbr(rpl_parent_t *parent);
|
||||
void rpl_print_neighbor_list(void);
|
||||
|
Loading…
Reference in New Issue
Block a user