Contiki 3.x
collect-neighbor.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2006, Swedish Institute of Computer Science.
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
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  */
32 
33 /**
34  * \file
35  * Radio neighborhood management
36  * \author
37  * Adam Dunkels <adam@sics.se>
38  */
39 
40 /**
41  * \addtogroup rimeneighbor
42  * @{
43  */
44 
45 #include <limits.h>
46 #include <stdio.h>
47 
48 #include "contiki.h"
49 #include "lib/memb.h"
50 #include "lib/list.h"
51 
53 #include "net/rime/collect.h"
54 
55 #ifdef COLLECT_NEIGHBOR_CONF_MAX_COLLECT_NEIGHBORS
56 #define MAX_COLLECT_NEIGHBORS COLLECT_NEIGHBOR_CONF_MAX_COLLECT_NEIGHBORS
57 #else /* COLLECT_NEIGHBOR_CONF_MAX_COLLECT_NEIGHBORS */
58 #define MAX_COLLECT_NEIGHBORS 8
59 #endif /* COLLECT_NEIGHBOR_CONF_MAX_COLLECT_NEIGHBORS */
60 
61 #define RTMETRIC_MAX COLLECT_MAX_DEPTH
62 
63 MEMB(collect_neighbors_mem, struct collect_neighbor, MAX_COLLECT_NEIGHBORS);
64 
65 #define MAX_AGE 180
66 #define MAX_LE_AGE 10
67 #define PERIODIC_INTERVAL CLOCK_SECOND * 60
68 
69 #define EXPECTED_CONGESTION_DURATION CLOCK_SECOND * 240
70 #define CONGESTION_PENALTY 8 * COLLECT_LINK_ESTIMATE_UNIT
71 
72 #define DEBUG 0
73 #if DEBUG
74 #include <stdio.h>
75 #define PRINTF(...) printf(__VA_ARGS__)
76 #else
77 #define PRINTF(...)
78 #endif
79 
80 /*---------------------------------------------------------------------------*/
81 static void
82 periodic(void *ptr)
83 {
84  struct collect_neighbor_list *neighbor_list;
85  struct collect_neighbor *n;
86 
87  neighbor_list = ptr;
88 
89  /* Go through all collect_neighbors and increase their age. */
90  for(n = list_head(neighbor_list->list); n != NULL; n = list_item_next(n)) {
91  n->age++;
92  n->le_age++;
93  }
94  for(n = list_head(neighbor_list->list); n != NULL; n = list_item_next(n)) {
95  if(n->le_age == MAX_LE_AGE) {
97  n->le_age = 0;
98  }
99  if(n->age == MAX_AGE) {
100  memb_free(&collect_neighbors_mem, n);
101  list_remove(neighbor_list->list, n);
102  n = list_head(neighbor_list->list);
103  }
104  }
105  ctimer_set(&neighbor_list->periodic, PERIODIC_INTERVAL,
106  periodic, neighbor_list);
107 }
108 /*---------------------------------------------------------------------------*/
109 void
110 collect_neighbor_init(void)
111 {
112  static uint8_t initialized = 0;
113  if(initialized == 0) {
114  initialized = 1;
115  memb_init(&collect_neighbors_mem);
116  }
117 }
118 /*---------------------------------------------------------------------------*/
119 void
120 collect_neighbor_list_new(struct collect_neighbor_list *neighbors_list)
121 {
122  LIST_STRUCT_INIT(neighbors_list, list);
123  list_init(neighbors_list->list);
124  ctimer_set(&neighbors_list->periodic, CLOCK_SECOND, periodic, neighbors_list);
125 }
126 /*---------------------------------------------------------------------------*/
127 struct collect_neighbor *
128 collect_neighbor_list_find(struct collect_neighbor_list *neighbors_list,
129  const linkaddr_t *addr)
130 {
131  struct collect_neighbor *n;
132  if(neighbors_list == NULL) {
133  return NULL;
134  }
135  for(n = list_head(neighbors_list->list); n != NULL; n = list_item_next(n)) {
136  if(linkaddr_cmp(&n->addr, addr)) {
137  return n;
138  }
139  }
140  return NULL;
141 }
142 /*---------------------------------------------------------------------------*/
143 int
144 collect_neighbor_list_add(struct collect_neighbor_list *neighbors_list,
145  const linkaddr_t *addr, uint16_t nrtmetric)
146 {
147  struct collect_neighbor *n;
148 
149  if(addr == NULL) {
150  PRINTF("collect_neighbor_list_add: attempt to add NULL addr\n");
151  return 0;
152  }
153 
154  if(neighbors_list == NULL) {
155  return 0;
156  }
157 
158  PRINTF("collect_neighbor_add: adding %d.%d\n", addr->u8[0], addr->u8[1]);
159 
160  /* Check if the collect_neighbor is already on the list. */
161  for(n = list_head(neighbors_list->list); n != NULL; n = list_item_next(n)) {
162  if(linkaddr_cmp(&n->addr, addr)) {
163  PRINTF("collect_neighbor_add: already on list %d.%d\n",
164  addr->u8[0], addr->u8[1]);
165  break;
166  }
167  }
168 
169  /* If the collect_neighbor was not on the list, we try to allocate memory
170  for it. */
171  if(n == NULL) {
172  PRINTF("collect_neighbor_add: not on list, allocating %d.%d\n",
173  addr->u8[0], addr->u8[1]);
174  n = memb_alloc(&collect_neighbors_mem);
175  if(n != NULL) {
176  list_add(neighbors_list->list, n);
177  }
178  }
179 
180  /* If we could not allocate memory, we try to recycle an old
181  neighbor. XXX Should also look for the one with the worst
182  rtmetric (not link esimate). XXX Also make sure that we don't
183  replace a neighbor with a neighbor that has a worse metric. */
184  if(n == NULL) {
185  uint16_t worst_rtmetric;
186  struct collect_neighbor *worst_neighbor;
187 
188  /* Find the neighbor that has the highest rtmetric. This is the
189  neighbor that we are least likely to be using in the
190  future. But we also need to make sure that the neighbor we are
191  currently adding is not worst than the one we would be
192  replacing. If so, we don't put the new neighbor on the list. */
193  worst_rtmetric = 0;
194  worst_neighbor = NULL;
195 
196  for(n = list_head(neighbors_list->list);
197  n != NULL; n = list_item_next(n)) {
198  if(n->rtmetric > worst_rtmetric) {
199  worst_neighbor = n;
200  worst_rtmetric = n->rtmetric;
201  }
202  }
203 
204  /* Only add this new neighbor if its rtmetric is lower than the
205  one it would replace. */
206  if(nrtmetric < worst_rtmetric) {
207  n = worst_neighbor;
208  }
209  if(n != NULL) {
210  PRINTF("collect_neighbor_add: not on list, not allocated, recycling %d.%d\n",
211  n->addr.u8[0], n->addr.u8[1]);
212  }
213  }
214 
215  if(n != NULL) {
216  n->age = 0;
217  linkaddr_copy(&n->addr, addr);
218  n->rtmetric = nrtmetric;
220  n->le_age = 0;
221  return 1;
222  }
223  return 0;
224 }
225 /*---------------------------------------------------------------------------*/
226 list_t
227 collect_neighbor_list(struct collect_neighbor_list *neighbors_list)
228 {
229  if(neighbors_list == NULL) {
230  return NULL;
231  }
232 
233  return neighbors_list->list;
234 }
235 /*---------------------------------------------------------------------------*/
236 void
237 collect_neighbor_list_remove(struct collect_neighbor_list *neighbors_list,
238  const linkaddr_t *addr)
239 {
240  struct collect_neighbor *n;
241 
242  if(neighbors_list == NULL) {
243  return;
244  }
245 
246  n = collect_neighbor_list_find(neighbors_list, addr);
247 
248  if(n != NULL) {
249  list_remove(neighbors_list->list, n);
250  memb_free(&collect_neighbors_mem, n);
251  }
252 }
253 /*---------------------------------------------------------------------------*/
254 struct collect_neighbor *
255 collect_neighbor_list_best(struct collect_neighbor_list *neighbors_list)
256 {
257  struct collect_neighbor *n, *best;
258  uint16_t rtmetric;
259 
260  rtmetric = RTMETRIC_MAX;
261  best = NULL;
262 
263  if(neighbors_list == NULL) {
264  return NULL;
265  }
266 
267  /* PRINTF("%d: ", node_id);*/
268  PRINTF("collect_neighbor_best: ");
269 
270  /* Find the neighbor with the lowest rtmetric + linkt estimate. */
271  for(n = list_head(neighbors_list->list); n != NULL; n = list_item_next(n)) {
272  PRINTF("%d.%d %d+%d=%d, ",
273  n->addr.u8[0], n->addr.u8[1],
274  n->rtmetric, collect_neighbor_link_estimate(n),
275  collect_neighbor_rtmetric(n));
276  if(collect_neighbor_rtmetric_link_estimate(n) < rtmetric) {
277  rtmetric = collect_neighbor_rtmetric_link_estimate(n);
278  best = n;
279  }
280  }
281  PRINTF("\n");
282 
283  return best;
284 }
285 /*---------------------------------------------------------------------------*/
286 int
287 collect_neighbor_list_num(struct collect_neighbor_list *neighbors_list)
288 {
289  if(neighbors_list == NULL) {
290  return 0;
291  }
292 
293  PRINTF("collect_neighbor_num %d\n", list_length(neighbors_list->list));
294  return list_length(neighbors_list->list);
295 }
296 /*---------------------------------------------------------------------------*/
297 struct collect_neighbor *
298 collect_neighbor_list_get(struct collect_neighbor_list *neighbors_list, int num)
299 {
300  int i;
301  struct collect_neighbor *n;
302 
303  if(neighbors_list == NULL) {
304  return NULL;
305  }
306 
307  PRINTF("collect_neighbor_get %d\n", num);
308 
309  i = 0;
310  for(n = list_head(neighbors_list->list); n != NULL; n = list_item_next(n)) {
311  if(i == num) {
312  PRINTF("collect_neighbor_get found %d.%d\n",
313  n->addr.u8[0], n->addr.u8[1]);
314  return n;
315  }
316  i++;
317  }
318  return NULL;
319 }
320 /*---------------------------------------------------------------------------*/
321 void
322 collect_neighbor_list_purge(struct collect_neighbor_list *neighbors_list)
323 {
324  if(neighbors_list == NULL) {
325  return;
326  }
327 
328  while(list_head(neighbors_list->list) != NULL) {
329  memb_free(&collect_neighbors_mem, list_pop(neighbors_list->list));
330  }
331 }
332 /*---------------------------------------------------------------------------*/
333 void
334 collect_neighbor_update_rtmetric(struct collect_neighbor *n, uint16_t rtmetric)
335 {
336  if(n != NULL) {
337  PRINTF("%d.%d: collect_neighbor_update %d.%d rtmetric %d\n",
339  n->addr.u8[0], n->addr.u8[1], rtmetric);
340  n->rtmetric = rtmetric;
341  n->age = 0;
342  }
343 }
344 /*---------------------------------------------------------------------------*/
345 void
346 collect_neighbor_tx_fail(struct collect_neighbor *n, uint16_t num_tx)
347 {
348  if(n == NULL) {
349  return;
350  }
351  collect_link_estimate_update_tx_fail(&n->le, num_tx);
352  n->le_age = 0;
353  n->age = 0;
354 }
355 /*---------------------------------------------------------------------------*/
356 void
357 collect_neighbor_tx(struct collect_neighbor *n, uint16_t num_tx)
358 {
359  if(n == NULL) {
360  return;
361  }
362  collect_link_estimate_update_tx(&n->le, num_tx);
363  n->le_age = 0;
364  n->age = 0;
365 }
366 /*---------------------------------------------------------------------------*/
367 void
368 collect_neighbor_rx(struct collect_neighbor *n)
369 {
370  if(n == NULL) {
371  return;
372  }
374  n->age = 0;
375 }
376 /*---------------------------------------------------------------------------*/
377 uint16_t
378 collect_neighbor_link_estimate(struct collect_neighbor *n)
379 {
380  if(n == NULL) {
381  return 0;
382  }
383  if(collect_neighbor_is_congested(n)) {
384  /* printf("Congested %d.%d, sould return %d, returning %d\n",
385  n->addr.u8[0], n->addr.u8[1],
386  collect_link_estimate(&n->le),
387  collect_link_estimate(&n->le) + CONGESTION_PENALTY);*/
388  return collect_link_estimate(&n->le) + CONGESTION_PENALTY;
389  } else {
390  return collect_link_estimate(&n->le);
391  }
392 }
393 /*---------------------------------------------------------------------------*/
394 uint16_t
395 collect_neighbor_rtmetric_link_estimate(struct collect_neighbor *n)
396 {
397  if(n == NULL) {
398  return 0;
399  }
400  return n->rtmetric + collect_link_estimate(&n->le);
401 }
402 /*---------------------------------------------------------------------------*/
403 uint16_t
404 collect_neighbor_rtmetric(struct collect_neighbor *n)
405 {
406  if(n == NULL) {
407  return 0;
408  }
409 
410  return n->rtmetric;
411 }
412 /*---------------------------------------------------------------------------*/
413 void
414 collect_neighbor_set_congested(struct collect_neighbor *n)
415 {
416  if(n == NULL) {
417  return;
418  }
419  timer_set(&n->congested_timer, EXPECTED_CONGESTION_DURATION);
420 }
421 /*---------------------------------------------------------------------------*/
422 int
423 collect_neighbor_is_congested(struct collect_neighbor *n)
424 {
425  if(n == NULL) {
426  return 0;
427  }
428 
429  if(timer_expired(&n->congested_timer)) {
430  return 0;
431  } else {
432  return 1;
433  }
434 }
435 /*---------------------------------------------------------------------------*/
436 /** @} */
uint16_t collect_link_estimate(struct collect_link_estimate *le)
Compute the link estimate metric for a link estimate.
void list_remove(list_t list, void *item)
Remove a specific element from a list.
Definition: list.c:240
void collect_link_estimate_update_rx(struct collect_link_estimate *n)
Update a link estimate when a packet has been received.
static uip_ds6_addr_t * addr
Pointer to a router list entry.
Definition: uip-nd6.c:124
#define MEMB(name, structure, num)
Declare a memory block.
Definition: memb.h:89
void timer_set(struct timer *t, clock_time_t interval)
Set a timer.
Definition: timer.c:64
void * list_pop(list_t list)
Remove the first object on a list.
Definition: list.c:218
void * list_item_next(void *item)
Get the next item following this item.
Definition: list.c:325
Header file for the Contiki radio neighborhood management
void ** list_t
The linked list type.
Definition: list.h:133
void list_init(list_t list)
Initialize a list.
Definition: list.c:66
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
Definition: memb.c:52
void * list_head(list_t list)
Get a pointer to the first element of a list.
Definition: list.c:83
#define NULL
The null pointer.
void collect_link_estimate_update_tx_fail(struct collect_link_estimate *le, uint8_t tx)
Update a link estimate when a packet has failed to be sent.
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition: list.c:143
#define CLOCK_SECOND
A second, measured in system clock time.
Definition: clock.h:82
Linked list manipulation routines.
Header file for hop-by-hop reliable data collection
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
Memory block allocation routines.
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two Rime addresses.
Definition: linkaddr.c:66
void linkaddr_copy(linkaddr_t *dest, const linkaddr_t *src)
Copy a Rime address.
Definition: linkaddr.c:60
linkaddr_t linkaddr_node_addr
The Rime address of the node.
Definition: linkaddr.c:48
int list_length(list_t list)
Get the length of a list.
Definition: list.c:275
#define LIST_STRUCT_INIT(struct_ptr, name)
Initialize a linked list that is part of a structure.
Definition: list.h:122
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
Definition: memb.c:59
void collect_link_estimate_update_tx(struct collect_link_estimate *le, uint8_t tx)
Update a link estimate when a packet has been sent.
char memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
Definition: memb.c:79
void collect_link_estimate_new(struct collect_link_estimate *le)
Initialize a new link estimate.
int timer_expired(struct timer *t)
Check if a timer has expired.
Definition: timer.c:122