Contiki-NG
rpl-nbr-policy.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014-2015, Yanzi Networks AB.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * 3. Neither the name of the copyright holders nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  */
30 /**
31  * \addtogroup uip
32  * @{
33  */
34 
35 
36 /**
37  * \file
38  *
39  * Default RPL NBR policy
40  * decides when to add a new discovered node to the nbr table from RPL.
41  *
42  * \author Joakim Eriksson <joakime@sics.se>
43  * Contributors: Niclas Finne <nfi@sics.se>, Oriol PiƱol <oriol@yanzi.se>,
44  *
45  */
46 
47 #include "net/routing/rpl-classic/rpl-private.h"
48 #include "net/nbr-table.h"
49 #include "net/ipv6/uip-ds6-nbr.h"
50 #include "net/ipv6/uip-ds6-route.h"
51 
52 #include "sys/log.h"
53 
54 #define LOG_MODULE "RPL"
55 #define LOG_LEVEL LOG_LEVEL_RPL
56 
57 /*
58  * Policy for neighbor adds
59  * - one node is locked (default route)
60  * - max X children (nexthops)
61  * - max Y "best parents"
62  * => at least MAX_NBRS - (Y + X + 1) free slots for other.
63  *
64  * NOTE: this policy assumes that all neighbors end up being IPv6
65  * neighbors and are not only MAC neighbors.
66  */
67 #define MAX_CHILDREN (NBR_TABLE_MAX_NEIGHBORS - 2)
68 #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
69 
70 static int num_parents; /* any node that are possible parents */
71 static int num_children; /* all children that we have as nexthop */
72 static int num_free;
73 static linkaddr_t *worst_rank_nbr; /* the parent that has the worst rank */
74 static rpl_rank_t worst_rank;
75 /*---------------------------------------------------------------------------*/
76 #if LOG_DBG_ENABLED
77 /*
78  * This create a periodic call of the update_nbr function that will print
79  * useful debugging information when in DEBUG_FULL mode
80  */
81 static void update_nbr(void);
82 static struct ctimer periodic_timer;
83 static int timer_init = 0;
84 static void
85 handle_periodic_timer(void *ptr)
86 {
87  update_nbr();
88  ctimer_restart(&periodic_timer);
89 }
90 #endif /* LOG_DBG_ENABLED */
91 /*---------------------------------------------------------------------------*/
92 static void
93 update_nbr(void)
94 {
96  rpl_parent_t *parent;
97  int num_used;
98  int is_used;
99  rpl_rank_t rank;
100 
101 #if LOG_DBG_ENABLED
102  if(!timer_init) {
103  timer_init = 1;
104  ctimer_set(&periodic_timer, 60 * CLOCK_SECOND,
105  &handle_periodic_timer, NULL);
106  }
107 #endif /* LOG_DBG_ENABLED */
108 
109  worst_rank = 0;
110  worst_rank_nbr = NULL;
111  num_used = 0;
112  num_parents = 0;
113  num_children = 0;
114 
115  nbr = nbr_table_head(ds6_neighbors);
116  while(nbr != NULL) {
117  linkaddr_t *lladdr = nbr_table_get_lladdr(ds6_neighbors, nbr);
118  is_used = 0;
119 
120  /*
121  * Check if this neighbor is used as nexthop and therefor being a
122  * RPL child.
123  */
124 
125  if(uip_ds6_route_is_nexthop(&nbr->ipaddr) != 0) {
126  is_used++;
127  num_children++;
128  }
129 
130  parent = rpl_get_parent((uip_lladdr_t *)lladdr);
131  if(parent != NULL) {
132  num_parents++;
133 
134  if(parent->dag != NULL && parent->dag->preferred_parent == parent) {
135  /*
136  * This is the preferred parent for the DAG and must not be removed
137  * Note: this assumes that only RPL adds default routes.
138  */
139  } else if(is_used == 0 && worst_rank < RPL_INFINITE_RANK &&
140  parent->rank > 0 &&
141  parent->dag != NULL &&
142  parent->dag->instance != NULL &&
143  (rank = parent->dag->instance->of->rank_via_parent(parent)) > worst_rank) {
144  /* This is the worst-rank neighbor - this is a good candidate for removal */
145  worst_rank = rank;
146  worst_rank_nbr = lladdr;
147  }
148  /* add to is_used after evaluation of is_used above */
149  is_used++;
150  }
151 
152  if(is_used == 0) {
153  /* This neighbor is neither parent or child and can be safely removed */
154  worst_rank_nbr = lladdr;
155  worst_rank = RPL_INFINITE_RANK;
156  } else if(is_used > 1) {
157  LOG_DBG("nbr-policy: *** neighbor is both child and candidate parent: ");
158  LOG_DBG_LLADDR(lladdr);
159  LOG_DBG_("\n");
160  }
161 
162  nbr = nbr_table_next(ds6_neighbors, nbr);
163  num_used++;
164  }
165  /* how many more IP neighbors can be have? */
166  num_free = NBR_TABLE_MAX_NEIGHBORS - num_used;
167 
168  LOG_DBG("nbr-policy: free: %d, children: %d, parents: %d routes: %d\n",
169  num_free, num_children, num_parents, uip_ds6_route_num_routes());
170 }
171 /*---------------------------------------------------------------------------*/
172 /* Called whenever we get a unicast DIS - e.g. someone that already
173  have this node in its table - since it is a unicast */
174 const linkaddr_t *
175 find_removable_dis(uip_ipaddr_t *from)
176 {
177 
178  update_nbr();
179  if(num_free > 0) {
180  /* there are free entries (e.g. unsused by RPL and ND6) but since it is
181  used by other modules we can not pick these entries for removal. */
182  LOG_DBG("nbr-policy: num-free > 0 = %d - Other for RPL/ND6 unused NBR entry exists.\n",
183  num_free);
184  }
185  if(num_children < MAX_CHILDREN) {
186  return worst_rank_nbr;
187  }
188  return NULL;
189 }
190 /*---------------------------------------------------------------------------*/
191 const linkaddr_t *
192 find_removable_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
193 {
194  rpl_instance_t *instance;
195 
196  update_nbr();
197 
198  instance = rpl_get_instance(dio->instance_id);
199  if(instance == NULL || instance->current_dag == NULL) {
200  LOG_WARN("nbr-policy: did not find instance id: %d\n", dio->instance_id);
201  return NULL;
202  }
203 
204  /* Add the new neighbor only if it is better than the worst parent. */
205  if(dio->rank + instance->min_hoprankinc < worst_rank - instance->min_hoprankinc / 2) {
206  /* Found *great* neighbor - add! */
207  LOG_DBG("nbr-policy: DIO rank %u, worst_rank %u -- add to cache\n",
208  dio->rank, worst_rank);
209 
210  return worst_rank_nbr;
211  }
212 
213  LOG_DBG("nbr-policy: DIO rank %u, worst_rank %u -- do not add to cache\n",
214  dio->rank, worst_rank);
215  return NULL;
216 }
217 /*---------------------------------------------------------------------------*/
218 const linkaddr_t *
219 find_removable_dao(uip_ipaddr_t *from, rpl_instance_t *instance)
220 {
221  int max = MAX_CHILDREN;
222  update_nbr();
223 
224  if(instance != NULL) {
225  /* No need to reserve space for parents for RPL ROOT */
226  if(instance->current_dag->rank == ROOT_RANK(instance)) {
227  max = NBR_TABLE_MAX_NEIGHBORS;
228  }
229  }
230 
231  /* Check if this DAO sender is not yet neighbor and there is already too
232  many children. */
233  if(num_children >= max) {
234  LOG_ERR("nbr-policy: can not add another child - already at max.\n");
235  return NULL;
236  }
237  /* remove the worst ranked nbr */
238  return worst_rank_nbr;
239 }
240 /*---------------------------------------------------------------------------*/
241 const linkaddr_t *
242 rpl_nbr_policy_find_removable(nbr_table_reason_t reason,void * data)
243 {
244  /* When we get the DIO/DAO/DIS we know that UIP contains the
245  incoming packet */
246  switch(reason) {
247  case NBR_TABLE_REASON_RPL_DIO:
248  return find_removable_dio(&UIP_IP_BUF->srcipaddr, data);
249  case NBR_TABLE_REASON_RPL_DAO:
250  return find_removable_dao(&UIP_IP_BUF->srcipaddr, data);
251  case NBR_TABLE_REASON_RPL_DIS:
252  return find_removable_dis(&UIP_IP_BUF->srcipaddr);
253  default:
254  return NULL;
255  }
256 }
257 /*---------------------------------------------------------------------------*/
258 /** @}*/
#define UIP_IP_BUF
Pointer to IP header.
Definition: uip-nd6.c:97
static uip_ds6_nbr_t * nbr
Pointer to llao option in uip_buf.
Definition: uip-nd6.c:115
RPL instance structure.
Definition: rpl.h:219
#define ROOT_RANK
Rank of a root node.
Definition: rpl-types.h:78
IPv6 Neighbor cache (link-layer/IPv6 address mapping)
#define CLOCK_SECOND
A second, measured in system clock time.
Definition: clock.h:82
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
void ctimer_restart(struct ctimer *c)
Restart a callback timer from the current point in time.
Definition: ctimer.c:137
Header file for routing table manipulation.
Header file for the logging system
An entry in the nbr cache.
Definition: uip-ds6-nbr.h:69