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  int found;
258  struct collect_neighbor *n, *best;
259  uint16_t rtmetric;
260 
261  rtmetric = RTMETRIC_MAX;
262  best = NULL;
263  found = 0;
264 
265  if(neighbors_list == NULL) {
266  return NULL;
267  }
268 
269  /* PRINTF("%d: ", node_id);*/
270  PRINTF("collect_neighbor_best: ");
271 
272  /* Find the neighbor with the lowest rtmetric + linkt estimate. */
273  for(n = list_head(neighbors_list->list); n != NULL; n = list_item_next(n)) {
274  PRINTF("%d.%d %d+%d=%d, ",
275  n->addr.u8[0], n->addr.u8[1],
276  n->rtmetric, collect_neighbor_link_estimate(n),
277  collect_neighbor_rtmetric(n));
278  if(collect_neighbor_rtmetric_link_estimate(n) < rtmetric) {
279  rtmetric = collect_neighbor_rtmetric_link_estimate(n);
280  best = n;
281  }
282  }
283  PRINTF("\n");
284 
285  return best;
286 }
287 /*---------------------------------------------------------------------------*/
288 int
289 collect_neighbor_list_num(struct collect_neighbor_list *neighbors_list)
290 {
291  if(neighbors_list == NULL) {
292  return 0;
293  }
294 
295  PRINTF("collect_neighbor_num %d\n", list_length(neighbors_list->list));
296  return list_length(neighbors_list->list);
297 }
298 /*---------------------------------------------------------------------------*/
299 struct collect_neighbor *
300 collect_neighbor_list_get(struct collect_neighbor_list *neighbors_list, int num)
301 {
302  int i;
303  struct collect_neighbor *n;
304 
305  if(neighbors_list == NULL) {
306  return NULL;
307  }
308 
309  PRINTF("collect_neighbor_get %d\n", num);
310 
311  i = 0;
312  for(n = list_head(neighbors_list->list); n != NULL; n = list_item_next(n)) {
313  if(i == num) {
314  PRINTF("collect_neighbor_get found %d.%d\n",
315  n->addr.u8[0], n->addr.u8[1]);
316  return n;
317  }
318  i++;
319  }
320  return NULL;
321 }
322 /*---------------------------------------------------------------------------*/
323 void
324 collect_neighbor_list_purge(struct collect_neighbor_list *neighbors_list)
325 {
326  if(neighbors_list == NULL) {
327  return;
328  }
329 
330  while(list_head(neighbors_list->list) != NULL) {
331  memb_free(&collect_neighbors_mem, list_pop(neighbors_list->list));
332  }
333 }
334 /*---------------------------------------------------------------------------*/
335 void
336 collect_neighbor_update_rtmetric(struct collect_neighbor *n, uint16_t rtmetric)
337 {
338  if(n != NULL) {
339  PRINTF("%d.%d: collect_neighbor_update %d.%d rtmetric %d\n",
341  n->addr.u8[0], n->addr.u8[1], rtmetric);
342  n->rtmetric = rtmetric;
343  n->age = 0;
344  }
345 }
346 /*---------------------------------------------------------------------------*/
347 void
348 collect_neighbor_tx_fail(struct collect_neighbor *n, uint16_t num_tx)
349 {
350  if(n == NULL) {
351  return;
352  }
353  collect_link_estimate_update_tx_fail(&n->le, num_tx);
354  n->le_age = 0;
355  n->age = 0;
356 }
357 /*---------------------------------------------------------------------------*/
358 void
359 collect_neighbor_tx(struct collect_neighbor *n, uint16_t num_tx)
360 {
361  if(n == NULL) {
362  return;
363  }
364  collect_link_estimate_update_tx(&n->le, num_tx);
365  n->le_age = 0;
366  n->age = 0;
367 }
368 /*---------------------------------------------------------------------------*/
369 void
370 collect_neighbor_rx(struct collect_neighbor *n)
371 {
372  if(n == NULL) {
373  return;
374  }
376  n->age = 0;
377 }
378 /*---------------------------------------------------------------------------*/
379 uint16_t
380 collect_neighbor_link_estimate(struct collect_neighbor *n)
381 {
382  if(n == NULL) {
383  return 0;
384  }
385  if(collect_neighbor_is_congested(n)) {
386  /* printf("Congested %d.%d, sould return %d, returning %d\n",
387  n->addr.u8[0], n->addr.u8[1],
388  collect_link_estimate(&n->le),
389  collect_link_estimate(&n->le) + CONGESTION_PENALTY);*/
390  return collect_link_estimate(&n->le) + CONGESTION_PENALTY;
391  } else {
392  return collect_link_estimate(&n->le);
393  }
394 }
395 /*---------------------------------------------------------------------------*/
396 uint16_t
397 collect_neighbor_rtmetric_link_estimate(struct collect_neighbor *n)
398 {
399  if(n == NULL) {
400  return 0;
401  }
402  return n->rtmetric + collect_link_estimate(&n->le);
403 }
404 /*---------------------------------------------------------------------------*/
405 uint16_t
406 collect_neighbor_rtmetric(struct collect_neighbor *n)
407 {
408  if(n == NULL) {
409  return 0;
410  }
411 
412  return n->rtmetric;
413 }
414 /*---------------------------------------------------------------------------*/
415 void
416 collect_neighbor_set_congested(struct collect_neighbor *n)
417 {
418  if(n == NULL) {
419  return;
420  }
421  timer_set(&n->congested_timer, EXPECTED_CONGESTION_DURATION);
422 }
423 /*---------------------------------------------------------------------------*/
424 int
425 collect_neighbor_is_congested(struct collect_neighbor *n)
426 {
427  if(n == NULL) {
428  return 0;
429  }
430 
431  if(timer_expired(&n->congested_timer)) {
432  return 0;
433  } else {
434  return 1;
435  }
436 }
437 /*---------------------------------------------------------------------------*/
438 /** @} */
void * list_pop(list_t list)
Remove the first object on a list.
Definition: list.c:218
Linked list manipulation routines.
linkaddr_t linkaddr_node_addr
The Rime address of the node.
Definition: linkaddr.c:48
void collect_link_estimate_update_tx(struct collect_link_estimate *le, uint8_t tx)
Update a link estimate when a packet has been sent.
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
Definition: memb.c:52
void ** list_t
The linked list type.
Definition: list.h:133
Header file for hop-by-hop reliable data collection
void * list_item_next(void *item)
Get the next item following this item.
Definition: list.c:325
void timer_set(struct timer *t, clock_time_t interval)
Set a timer.
Definition: timer.c:64
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 * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
Definition: memb.c:59
#define NULL
The null pointer.
void list_remove(list_t list, void *item)
Remove a specific element from a list.
Definition: list.c:240
int list_length(list_t list)
Get the length of a list.
Definition: list.c:275
void linkaddr_copy(linkaddr_t *dest, const linkaddr_t *src)
Copy a Rime address.
Definition: linkaddr.c:60
void list_init(list_t list)
Initialize a list.
Definition: list.c:66
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
void * list_head(list_t list)
Get a pointer to the first element of a list.
Definition: list.c:83
void collect_link_estimate_new(struct collect_link_estimate *le)
Initialize a new link estimate.
#define MEMB(name, structure, num)
Declare a memory block.
Definition: memb.h:89
void collect_link_estimate_update_rx(struct collect_link_estimate *n)
Update a link estimate when a packet has been received.
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition: list.c:143
#define LIST_STRUCT_INIT(struct_ptr, name)
Initialize a linked list that is part of a structure.
Definition: list.h:122
Header file for the Contiki radio neighborhood management
uint16_t collect_link_estimate(struct collect_link_estimate *le)
Compute the link estimate metric for a link estimate.
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two Rime addresses.
Definition: linkaddr.c:66
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.
Memory block allocation routines.
int timer_expired(struct timer *t)
Check if a timer has expired.
Definition: timer.c:121
#define CLOCK_SECOND
A second, measured in system clock time.
Definition: clock.h:82