added nbr policy for Contiki RPL that avoids thrashing the nbr table with new entries all the time
This commit is contained in:
parent
d181bd9e6f
commit
3fd8c4db2d
|
@ -245,6 +245,18 @@
|
||||||
#define RPL_WITH_DAO_ACK 1
|
#define RPL_WITH_DAO_ACK 1
|
||||||
#endif /* RPL_CONF_WITH_DAO_ACK */
|
#endif /* RPL_CONF_WITH_DAO_ACK */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setting the DIO_REFRESH_DAO_ROUTES will make RPL always increase
|
||||||
|
* the DTSN (Destination Advertisement Trigger Sequence Number) when
|
||||||
|
* sending broadcast DIO. This is to get all children to re-register
|
||||||
|
* their DAO route.
|
||||||
|
* */
|
||||||
|
#ifdef RPL_CONF_DIO_REFRESH_DAO_ROUTES
|
||||||
|
#define RPL_DIO_REFRESH_DAO_ROUTES RPL_CONF_DIO_REFRESH_DAO_ROUTES
|
||||||
|
#else
|
||||||
|
#define RPL_DIO_REFRESH_DAO_ROUTES 0
|
||||||
|
#endif /* RPL_CONF_DIO_REFRESH_DAO_ROUTES */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RPL probing. When enabled, probes will be sent periodically to keep
|
* RPL probing. When enabled, probes will be sent periodically to keep
|
||||||
* parent link estimates up to date.
|
* parent link estimates up to date.
|
||||||
|
|
|
@ -1174,6 +1174,8 @@ rpl_local_repair(rpl_instance_t *instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl_reset_dio_timer(instance);
|
rpl_reset_dio_timer(instance);
|
||||||
|
/* Request refresh of DAO registrations next DIO */
|
||||||
|
RPL_LOLLIPOP_INCREMENT(instance->dtsn_out);
|
||||||
|
|
||||||
RPL_STAT(rpl_stats.local_repairs++);
|
RPL_STAT(rpl_stats.local_repairs++);
|
||||||
}
|
}
|
||||||
|
@ -1250,6 +1252,23 @@ rpl_process_parent_event(rpl_instance_t *instance, rpl_parent_t *p)
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int
|
||||||
|
add_nbr_from_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
|
||||||
|
{
|
||||||
|
/* check if it is ok to add this nbr based on this DIO */
|
||||||
|
if(RPL_NBR_POLICY.check_add_from_dio(from, dio)) {
|
||||||
|
/* add this to the neighbor cache if not already there */
|
||||||
|
if(rpl_icmp6_update_nbr_table(from) == NULL) {
|
||||||
|
PRINTF("RPL: Out of memory, dropping DIO from ");
|
||||||
|
PRINT6ADDR(from);
|
||||||
|
PRINTF("\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
void
|
void
|
||||||
rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
|
rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
|
||||||
{
|
{
|
||||||
|
@ -1303,7 +1322,11 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
|
||||||
|
|
||||||
if(instance == NULL) {
|
if(instance == NULL) {
|
||||||
PRINTF("RPL: New instance detected (ID=%u): Joining...\n", dio->instance_id);
|
PRINTF("RPL: New instance detected (ID=%u): Joining...\n", dio->instance_id);
|
||||||
rpl_join_instance(from, dio);
|
if(add_nbr_from_dio(from, dio)) {
|
||||||
|
rpl_join_instance(from, dio);
|
||||||
|
} else {
|
||||||
|
PRINTF("RPL: Not joining since could not add parent\n");
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1315,6 +1338,10 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
|
||||||
if(dag == NULL) {
|
if(dag == NULL) {
|
||||||
#if RPL_MAX_DAG_PER_INSTANCE > 1
|
#if RPL_MAX_DAG_PER_INSTANCE > 1
|
||||||
PRINTF("RPL: Adding new DAG to known instance.\n");
|
PRINTF("RPL: Adding new DAG to known instance.\n");
|
||||||
|
if(!add_nbr_from_dio(from, dio)) {
|
||||||
|
PRINTF("RPL: Could not add new DAG, could not add parent\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
dag = rpl_add_dag(from, dio);
|
dag = rpl_add_dag(from, dio);
|
||||||
if(dag == NULL) {
|
if(dag == NULL) {
|
||||||
PRINTF("RPL: Failed to add DAG.\n");
|
PRINTF("RPL: Failed to add DAG.\n");
|
||||||
|
@ -1363,6 +1390,11 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
|
||||||
* whether to keep it in the set.
|
* whether to keep it in the set.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
if(!add_nbr_from_dio(from, dio)) {
|
||||||
|
PRINTF("RPL: Could not add parent based on DIO\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
p = rpl_find_parent(dag, from);
|
p = rpl_find_parent(dag, from);
|
||||||
if(p == NULL) {
|
if(p == NULL) {
|
||||||
previous_dag = find_parent_dag(instance, from);
|
previous_dag = find_parent_dag(instance, from);
|
||||||
|
|
|
@ -88,7 +88,6 @@ void RPL_DEBUG_DIO_INPUT(uip_ipaddr_t *, rpl_dio_t *);
|
||||||
void RPL_DEBUG_DAO_OUTPUT(rpl_parent_t *);
|
void RPL_DEBUG_DAO_OUTPUT(rpl_parent_t *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* TODO: should these variables be a part of the instance? */
|
|
||||||
static uint8_t dao_sequence = RPL_LOLLIPOP_INIT;
|
static uint8_t dao_sequence = RPL_LOLLIPOP_INIT;
|
||||||
|
|
||||||
extern rpl_of_t RPL_OF;
|
extern rpl_of_t RPL_OF;
|
||||||
|
@ -182,6 +181,32 @@ set16(uint8_t *buffer, int pos, uint16_t value)
|
||||||
buffer[pos++] = value & 0xff;
|
buffer[pos++] = value & 0xff;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
uip_ds6_nbr_t *
|
||||||
|
rpl_icmp6_update_nbr_table(uip_ipaddr_t *from)
|
||||||
|
{
|
||||||
|
uip_ds6_nbr_t *nbr;
|
||||||
|
|
||||||
|
if((nbr = uip_ds6_nbr_lookup(from)) == NULL) {
|
||||||
|
if((nbr = uip_ds6_nbr_add(from, (uip_lladdr_t *)
|
||||||
|
packetbuf_addr(PACKETBUF_ADDR_SENDER),
|
||||||
|
0, NBR_REACHABLE)) != NULL) {
|
||||||
|
PRINTF("RPL: Neighbor added to neighbor cache ");
|
||||||
|
PRINT6ADDR(from);
|
||||||
|
PRINTF(", ");
|
||||||
|
PRINTLLADDR((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
|
||||||
|
PRINTF("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(nbr != NULL) {
|
||||||
|
#if UIP_ND6_SEND_NA
|
||||||
|
/* set reachable timer if we added or found the nbr entry */
|
||||||
|
stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
|
||||||
|
#endif /* UIP_ND6_SEND_NA */
|
||||||
|
}
|
||||||
|
return nbr;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
static void
|
static void
|
||||||
dis_input(void)
|
dis_input(void)
|
||||||
{
|
{
|
||||||
|
@ -205,8 +230,20 @@ dis_input(void)
|
||||||
rpl_reset_dio_timer(instance);
|
rpl_reset_dio_timer(instance);
|
||||||
} else {
|
} else {
|
||||||
#endif /* !RPL_LEAF_ONLY */
|
#endif /* !RPL_LEAF_ONLY */
|
||||||
PRINTF("RPL: Unicast DIS, reply to sender\n");
|
/* Check if this neighbor should be added according to the policy. */
|
||||||
dio_output(instance, &UIP_IP_BUF->srcipaddr);
|
if(RPL_NBR_POLICY.check_add_from_dis(&UIP_IP_BUF->srcipaddr)) {
|
||||||
|
/* Add this to the neighbor cache if not already there */
|
||||||
|
if(rpl_icmp6_update_nbr_table(&UIP_IP_BUF->srcipaddr) == NULL) {
|
||||||
|
PRINTF("RPL: Out of Memory, not sending unicast DIO, DIS from ");
|
||||||
|
PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
|
||||||
|
PRINTF(", ");
|
||||||
|
PRINTLLADDR((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
|
||||||
|
PRINTF("\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PRINTF("RPL: Unicast DIS, reply to sender\n");
|
||||||
|
dio_output(instance, &UIP_IP_BUF->srcipaddr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,7 +290,6 @@ dio_input(void)
|
||||||
int i;
|
int i;
|
||||||
int len;
|
int len;
|
||||||
uip_ipaddr_t from;
|
uip_ipaddr_t from;
|
||||||
uip_ds6_nbr_t *nbr;
|
|
||||||
|
|
||||||
memset(&dio, 0, sizeof(dio));
|
memset(&dio, 0, sizeof(dio));
|
||||||
|
|
||||||
|
@ -274,32 +310,6 @@ dio_input(void)
|
||||||
PRINT6ADDR(&from);
|
PRINT6ADDR(&from);
|
||||||
PRINTF("\n");
|
PRINTF("\n");
|
||||||
|
|
||||||
if((nbr = uip_ds6_nbr_lookup(&from)) == NULL) {
|
|
||||||
if((nbr = uip_ds6_nbr_add(&from, (uip_lladdr_t *)
|
|
||||||
packetbuf_addr(PACKETBUF_ADDR_SENDER),
|
|
||||||
0, NBR_REACHABLE)) != NULL) {
|
|
||||||
#if UIP_ND6_SEND_NA
|
|
||||||
/* set reachable timer */
|
|
||||||
stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
|
|
||||||
#endif /* UIP_ND6_SEND_NA */
|
|
||||||
PRINTF("RPL: Neighbor added to neighbor cache ");
|
|
||||||
PRINT6ADDR(&from);
|
|
||||||
PRINTF(", ");
|
|
||||||
PRINTLLADDR((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
|
|
||||||
PRINTF("\n");
|
|
||||||
} else {
|
|
||||||
PRINTF("RPL: Out of memory, dropping DIO from ");
|
|
||||||
PRINT6ADDR(&from);
|
|
||||||
PRINTF(", ");
|
|
||||||
PRINTLLADDR((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
|
|
||||||
PRINTF("\n");
|
|
||||||
|
|
||||||
goto discard;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
PRINTF("RPL: Neighbor already in neighbor cache\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer_length = uip_len - uip_l3_icmp_hdr_len;
|
buffer_length = uip_len - uip_l3_icmp_hdr_len;
|
||||||
|
|
||||||
/* Process the DIO base option. */
|
/* Process the DIO base option. */
|
||||||
|
@ -796,29 +806,19 @@ dao_input(void)
|
||||||
|
|
||||||
PRINTF("RPL: adding DAO route\n");
|
PRINTF("RPL: adding DAO route\n");
|
||||||
|
|
||||||
if((nbr = uip_ds6_nbr_lookup(&dao_sender_addr)) == NULL) {
|
/* Check if we should add another neighbor based on DAO. */
|
||||||
if((nbr = uip_ds6_nbr_add(&dao_sender_addr,
|
if(!RPL_NBR_POLICY.check_add_from_dao(&dao_sender_addr)) {
|
||||||
(uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER),
|
/* Do not add the neighbor. */
|
||||||
0, NBR_REACHABLE)) != NULL) {
|
return;
|
||||||
#if UIP_ND6_SEND_NA
|
}
|
||||||
/* set reachable timer */
|
/* Update and add neighbor - if no room - fail. */
|
||||||
stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
|
if((nbr = rpl_icmp6_update_nbr_table(&dao_sender_addr)) == NULL) {
|
||||||
#endif /* UIP_ND6_SEND_NA */
|
PRINTF("RPL: Out of Memory, dropping DAO from ");
|
||||||
PRINTF("RPL: Neighbor added to neighbor cache ");
|
PRINT6ADDR(&dao_sender_addr);
|
||||||
PRINT6ADDR(&dao_sender_addr);
|
PRINTF(", ");
|
||||||
PRINTF(", ");
|
PRINTLLADDR((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
|
||||||
PRINTLLADDR((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
|
PRINTF("\n");
|
||||||
PRINTF("\n");
|
goto discard;
|
||||||
} else {
|
|
||||||
PRINTF("RPL: Out of Memory, dropping DAO from ");
|
|
||||||
PRINT6ADDR(&dao_sender_addr);
|
|
||||||
PRINTF(", ");
|
|
||||||
PRINTLLADDR((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
|
|
||||||
PRINTF("\n");
|
|
||||||
goto discard;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
PRINTF("RPL: Neighbor already in neighbor cache\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rep = rpl_add_route(dag, &prefix, prefixlen, &dao_sender_addr);
|
rep = rpl_add_route(dag, &prefix, prefixlen, &dao_sender_addr);
|
||||||
|
@ -834,9 +834,8 @@ dao_input(void)
|
||||||
goto discard;
|
goto discard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* State is all zeroes, set lifetime but no need for other initialization. */
|
||||||
rep->state.lifetime = RPL_LIFETIME(instance, lifetime);
|
rep->state.lifetime = RPL_LIFETIME(instance, lifetime);
|
||||||
/* rep->state.learned_from = learned_from; */
|
|
||||||
/* rep->state.nopath_received = 0; */
|
|
||||||
|
|
||||||
#if RPL_CONF_MULTICAST
|
#if RPL_CONF_MULTICAST
|
||||||
fwd_dao:
|
fwd_dao:
|
||||||
|
@ -877,8 +876,6 @@ fwd_dao:
|
||||||
ICMP6_RPL, RPL_CODE_DAO, buffer_length);
|
ICMP6_RPL, RPL_CODE_DAO, buffer_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ack sent immediately after forwarding (otherwise the packets is
|
|
||||||
corrupted. */
|
|
||||||
if(should_ack) {
|
if(should_ack) {
|
||||||
PRINTF("RPL: sending DAO ACK\n");
|
PRINTF("RPL: sending DAO ACK\n");
|
||||||
dao_ack_output(instance, &dao_sender_addr, sequence,
|
dao_ack_output(instance, &dao_sender_addr, sequence,
|
||||||
|
@ -897,30 +894,33 @@ handle_dao_retransmission(void *ptr)
|
||||||
rpl_parent_t *parent;
|
rpl_parent_t *parent;
|
||||||
uip_ipaddr_t prefix;
|
uip_ipaddr_t prefix;
|
||||||
rpl_instance_t *instance;
|
rpl_instance_t *instance;
|
||||||
parent = ptr;
|
|
||||||
|
|
||||||
|
parent = ptr;
|
||||||
if(parent == NULL || parent->dag == NULL || parent->dag->instance == NULL) {
|
if(parent == NULL || parent->dag == NULL || parent->dag->instance == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
instance = parent->dag->instance;
|
instance = parent->dag->instance;
|
||||||
|
|
||||||
if(instance->my_dao_transmissions >= RPL_DAO_MAX_RETRANSMISSIONS) {
|
if(instance->my_dao_transmissions >= RPL_DAO_MAX_RETRANSMISSIONS) {
|
||||||
/* no more retransmissions - what now ??? */
|
/* No more retransmissions - give up. */
|
||||||
if(instance->lifetime_unit == 0xffff && instance->default_lifetime == 0xff) {
|
if(instance->lifetime_unit == 0xffff && instance->default_lifetime == 0xff) {
|
||||||
/* RPL is using infinite lifetime for routes. This probably
|
/*
|
||||||
means that the root is running an old version that does not
|
* ContikiRPL was previously using infinite lifetime for routes
|
||||||
support DAO ack. Assume that everything is ok for now and
|
* and no DAO_ACK configured. This probably means that the root
|
||||||
let the normal repair mechanisms detect any problems. */
|
* and possibly other nodes might be running an old version that
|
||||||
|
* does not support DAO ack. Assume that everything is ok for
|
||||||
|
* now and let the normal repair mechanisms detect any problems.
|
||||||
|
*/
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(instance->of->dao_ack_callback) {
|
if(instance->of->dao_ack_callback) {
|
||||||
/* Inform about the timeout for taking decision on punishment */
|
/* Inform the objective function about the timeout. */
|
||||||
instance->of->dao_ack_callback(parent, RPL_DAO_ACK_TIMEOUT);
|
instance->of->dao_ack_callback(parent, RPL_DAO_ACK_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Perform local repair and hope to find another parent. */
|
||||||
rpl_local_repair(instance);
|
rpl_local_repair(instance);
|
||||||
/* give up this and hope to find another parent */
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1102,7 +1102,7 @@ dao_ack_input(void)
|
||||||
#endif /* DEBUG */
|
#endif /* DEBUG */
|
||||||
|
|
||||||
if(sequence == instance->my_dao_seqno) {
|
if(sequence == instance->my_dao_seqno) {
|
||||||
PRINTF("RPL: DAO ACK for me!\n");
|
PRINTF("RPL: DAO %s for me!\n", status < 128 ? "ACK" : "NACK");
|
||||||
|
|
||||||
/* always stop the retransmit timer when the ACK arrived */
|
/* always stop the retransmit timer when the ACK arrived */
|
||||||
ctimer_stop(&instance->dao_retransmit_timer);
|
ctimer_stop(&instance->dao_retransmit_timer);
|
||||||
|
|
244
core/net/rpl/rpl-nbr-policy.c
Normal file
244
core/net/rpl/rpl-nbr-policy.c
Normal file
|
@ -0,0 +1,244 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014-2015, Yanzi Networks AB.
|
||||||
|
* 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 copyright holders 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 COPYRIGHT HOLDERS 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
|
||||||
|
* COPYRIGHT HOLDERS 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* \addtogroup uip6
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
*
|
||||||
|
* Default RPL NBR policy
|
||||||
|
* decides when to add a new discovered node to the nbr table from RPL.
|
||||||
|
*
|
||||||
|
* \author Joakim Eriksson <joakime@sics.se>
|
||||||
|
* Contributors: Niclas Finne <nfi@sics.se>, Oriol Piñol <oriol@yanzi.se>,
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "net/rpl/rpl-private.h"
|
||||||
|
#include "net/nbr-table.h"
|
||||||
|
#include "net/ipv6/uip-ds6-nbr.h"
|
||||||
|
#include "net/ipv6/uip-ds6-route.h"
|
||||||
|
|
||||||
|
#define DEBUG DEBUG_NONE
|
||||||
|
#include "net/ip/uip-debug.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Policy for neighbor adds
|
||||||
|
* - one node is locked (default route)
|
||||||
|
* - max X children (nexthops)
|
||||||
|
* - max Y "best parents"
|
||||||
|
* => at least MAX_NBRS - (Y + X + 1) free slots for other.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MAX_CHILDREN (NBR_TABLE_MAX_NEIGHBORS - 3)
|
||||||
|
|
||||||
|
static int num_parents; /* any node that are possible parents */
|
||||||
|
static int num_children; /* all children that we have as nexthop */
|
||||||
|
static int num_free;
|
||||||
|
static uip_ds6_nbr_t *worst_rank_nbr; /* the parent that has the worst rank */
|
||||||
|
static rpl_rank_t worst_rank;
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
update_nbr(void)
|
||||||
|
{
|
||||||
|
uip_ds6_nbr_t *nbr;
|
||||||
|
rpl_parent_t *parent;
|
||||||
|
int num_used;
|
||||||
|
int is_used;
|
||||||
|
rpl_rank_t rank;
|
||||||
|
|
||||||
|
worst_rank = 0;
|
||||||
|
worst_rank_nbr = NULL;
|
||||||
|
num_used = 0;
|
||||||
|
num_parents = 0;
|
||||||
|
num_children = 0;
|
||||||
|
|
||||||
|
nbr = nbr_table_head(ds6_neighbors);
|
||||||
|
while(nbr != NULL) {
|
||||||
|
linkaddr_t *lladdr = nbr_table_get_lladdr(ds6_neighbors, nbr);
|
||||||
|
is_used = 0;
|
||||||
|
|
||||||
|
parent = rpl_get_parent((uip_lladdr_t *)lladdr);
|
||||||
|
if(parent != NULL) {
|
||||||
|
num_parents++;
|
||||||
|
is_used++;
|
||||||
|
|
||||||
|
if(parent->dag != NULL && parent->dag->preferred_parent == parent) {
|
||||||
|
/* This is the preferred parent for the DAG and must not be removed */
|
||||||
|
|
||||||
|
/* Note: this assumes that only RPL adds default routes. */
|
||||||
|
|
||||||
|
} else if(worst_rank < INFINITE_RANK &&
|
||||||
|
parent->rank > 0 &&
|
||||||
|
parent->dag != NULL &&
|
||||||
|
parent->dag->instance != NULL &&
|
||||||
|
(rank = parent->dag->instance->of->calculate_rank(parent, 0)) > worst_rank) {
|
||||||
|
/* This is the worst-rank neighbor - this is a good candidate for removal */
|
||||||
|
worst_rank = rank;
|
||||||
|
worst_rank_nbr = nbr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if this neighbor is used as nexthop and therefor being a
|
||||||
|
RPL child. */
|
||||||
|
if(uip_ds6_route_is_nexthop((uip_lladdr_t *)lladdr) != 0) {
|
||||||
|
is_used++;
|
||||||
|
num_children++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(is_used == 0) {
|
||||||
|
/* This neighbor is neither parent or child and can be safely removed */
|
||||||
|
worst_rank_nbr = nbr;
|
||||||
|
worst_rank = INFINITE_RANK;
|
||||||
|
} else if(is_used > 1) {
|
||||||
|
/* Both parent and child - this should never happen! */
|
||||||
|
PRINTF("NBR-POLICY: *** Neighbor is both child and candidate parent: ");
|
||||||
|
PRINTLLADDR((uip_lladdr_t *)lladdr);
|
||||||
|
PRINTF("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
nbr = nbr_table_next(ds6_neighbors, nbr);
|
||||||
|
num_used++;
|
||||||
|
}
|
||||||
|
/* how many more IP neighbors can be have? */
|
||||||
|
num_free = NBR_TABLE_MAX_NEIGHBORS - num_used;
|
||||||
|
|
||||||
|
PRINTF("NBR-POLICY: Free: %d, Children: %d, Parents: %d Routes: %d\n",
|
||||||
|
num_free, num_children, num_parents, uip_ds6_route_num_routes());
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int
|
||||||
|
remove_worst_nbr(void)
|
||||||
|
{
|
||||||
|
/* we assume that it is possible to remove the worst parent at the moment */
|
||||||
|
if(worst_rank_nbr != NULL) {
|
||||||
|
PRINTF("Removing worst ranked nbr ");
|
||||||
|
PRINTLLADDR((uip_lladdr_t*)nbr_table_get_lladdr(ds6_neighbors, worst_rank_nbr));
|
||||||
|
PRINTF(" with rank %d\n", worst_rank);
|
||||||
|
if(uip_ds6_nbr_rm(worst_rank_nbr)) {
|
||||||
|
worst_rank_nbr = NULL;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
PRINTF("FAILED to remove worst ranked nbr!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
PRINTF("FAILED to remove worst rank nbr - no found\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Called whenever we get a unicast DIS - e.g. someone that already
|
||||||
|
have this node in its table - since it is a unicast */
|
||||||
|
static int
|
||||||
|
check_add_from_dis(uip_ipaddr_t *from)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* do a lookup to see if it is alread there - then allow add/update */
|
||||||
|
if(uip_ds6_nbr_lookup(from)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
update_nbr();
|
||||||
|
if(num_free > 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(num_children < MAX_CHILDREN) {
|
||||||
|
return remove_worst_nbr();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int
|
||||||
|
check_add_from_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
|
||||||
|
{
|
||||||
|
rpl_instance_t *instance;
|
||||||
|
rpl_rank_t rank;
|
||||||
|
|
||||||
|
/* Do a lookup to see if it is already there - then allow add/update. */
|
||||||
|
if(uip_ds6_nbr_lookup(from)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
update_nbr();
|
||||||
|
|
||||||
|
/* If there is room for this neighbor just add it. */
|
||||||
|
if(num_free > 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
instance = rpl_get_instance(dio->instance_id);
|
||||||
|
if(instance == NULL || instance->current_dag == NULL) {
|
||||||
|
PRINTF("Did not find instance id: %d\n", dio->instance_id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add the new neighbor only if it is better than the preferred parent. */
|
||||||
|
rank = instance->of->calculate_rank(NULL, dio->rank);
|
||||||
|
if(rank < worst_rank - instance->min_hoprankinc / 2) {
|
||||||
|
/* Found *great* neighbor - add! */
|
||||||
|
PRINTF("Found better neighbor %d < %d - add to cache...\n",
|
||||||
|
rank, worst_rank);
|
||||||
|
|
||||||
|
return remove_worst_nbr();
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINTF("Found worse neighbor with new %d and old %d - NOT add to cache.\n",
|
||||||
|
rank, worst_rank);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int
|
||||||
|
check_add_from_dao(uip_ipaddr_t *from)
|
||||||
|
{
|
||||||
|
/* Do a lookup to see if it is alread there - then allow add/update. */
|
||||||
|
if(uip_ds6_nbr_lookup(from)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
update_nbr();
|
||||||
|
|
||||||
|
/* Check if this DAO sender is not yet neighbor and there is already too
|
||||||
|
many children. */
|
||||||
|
if(num_children >= MAX_CHILDREN) {
|
||||||
|
PRINTF("Can not add another child - already at max.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
const struct nbr_policy rpl_nbr_policy = {
|
||||||
|
check_add_from_dis,
|
||||||
|
check_add_from_dio,
|
||||||
|
check_add_from_dao
|
||||||
|
};
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/** @}*/
|
|
@ -124,8 +124,17 @@
|
||||||
#define RPL_NOPATH_REMOVAL_DELAY 60
|
#define RPL_NOPATH_REMOVAL_DELAY 60
|
||||||
#endif /* RPL_CONF_NOPATH_REMOVAL_DELAY */
|
#endif /* RPL_CONF_NOPATH_REMOVAL_DELAY */
|
||||||
|
|
||||||
|
#ifdef RPL_CONF_DAO_MAX_RETRANSMISSIONS
|
||||||
|
#define RPL_DAO_MAX_RETRANSMISSIONS RPL_CONF_DAO_MAX_RETRANSMISSIONS
|
||||||
|
#else
|
||||||
#define RPL_DAO_MAX_RETRANSMISSIONS 5
|
#define RPL_DAO_MAX_RETRANSMISSIONS 5
|
||||||
|
#endif /* RPL_CONF_DAO_MAX_RETRANSMISSIONS */
|
||||||
|
|
||||||
|
#ifdef RPL_CONF_DAO_RETRANSMISSION_TIMEOUT
|
||||||
|
#define RPL_DAO_RETRANSMISSION_TIMEOUT RPL_CONF_DAO_RETRANSMISSION_TIMEOUT
|
||||||
|
#else
|
||||||
#define RPL_DAO_RETRANSMISSION_TIMEOUT (5 * CLOCK_SECOND)
|
#define RPL_DAO_RETRANSMISSION_TIMEOUT (5 * CLOCK_SECOND)
|
||||||
|
#endif /* RPL_CONF_DAO_RETRANSMISSION_TIMEOUT */
|
||||||
|
|
||||||
/* Special value indicating immediate removal. */
|
/* Special value indicating immediate removal. */
|
||||||
#define RPL_ZERO_LIFETIME 0
|
#define RPL_ZERO_LIFETIME 0
|
||||||
|
@ -260,6 +269,24 @@ typedef struct rpl_stats rpl_stats_t;
|
||||||
|
|
||||||
extern rpl_stats_t rpl_stats;
|
extern rpl_stats_t rpl_stats;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct nbr_policy {
|
||||||
|
/** check if it is ok to add a nbr via UC DIS - positive => ok */
|
||||||
|
int (* check_add_from_dis)(uip_ipaddr_t *from);
|
||||||
|
int (* check_add_from_dio)(uip_ipaddr_t *from, rpl_dio_t *dio);
|
||||||
|
int (* check_add_from_dao)(uip_ipaddr_t *from);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef RPL_CONF_NBR_POLICY
|
||||||
|
#define RPL_NBR_POLICY RPL_CONF_NBR_POLICY
|
||||||
|
#else /* RPL_CONF_NBR_POLICY */
|
||||||
|
#define RPL_NBR_POLICY rpl_nbr_policy
|
||||||
|
#endif /* RPL_CONF_NBR_POLICY */
|
||||||
|
|
||||||
|
extern const struct nbr_policy RPL_NBR_POLICY;
|
||||||
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
/* RPL macros. */
|
/* RPL macros. */
|
||||||
|
|
||||||
|
@ -280,6 +307,7 @@ void dao_output(rpl_parent_t *, uint8_t lifetime);
|
||||||
void dao_output_target(rpl_parent_t *, uip_ipaddr_t *, uint8_t lifetime);
|
void dao_output_target(rpl_parent_t *, uip_ipaddr_t *, uint8_t lifetime);
|
||||||
void dao_ack_output(rpl_instance_t *, uip_ipaddr_t *, uint8_t, uint8_t);
|
void dao_ack_output(rpl_instance_t *, uip_ipaddr_t *, uint8_t, uint8_t);
|
||||||
void rpl_icmp6_register_handlers(void);
|
void rpl_icmp6_register_handlers(void);
|
||||||
|
uip_ds6_nbr_t *rpl_icmp6_update_nbr_table(uip_ipaddr_t *from);
|
||||||
|
|
||||||
/* RPL logic functions. */
|
/* RPL logic functions. */
|
||||||
void rpl_join_dag(uip_ipaddr_t *from, rpl_dio_t *dio);
|
void rpl_join_dag(uip_ipaddr_t *from, rpl_dio_t *dio);
|
||||||
|
|
|
@ -238,7 +238,6 @@ rpl_add_route(rpl_dag_t *dag, uip_ipaddr_t *prefix, int prefix_len,
|
||||||
|
|
||||||
rep->state.dag = dag;
|
rep->state.dag = dag;
|
||||||
rep->state.lifetime = RPL_LIFETIME(dag->instance, dag->instance->default_lifetime);
|
rep->state.lifetime = RPL_LIFETIME(dag->instance, dag->instance->default_lifetime);
|
||||||
/* rep->state.learned_from = RPL_ROUTE_FROM_INTERNAL; */
|
|
||||||
|
|
||||||
PRINTF("RPL: Added a route to ");
|
PRINTF("RPL: Added a route to ");
|
||||||
PRINT6ADDR(prefix);
|
PRINT6ADDR(prefix);
|
||||||
|
|
Loading…
Reference in a new issue