Contiki-Inga 3.x
nbr-table.c
1 /*
2  * Copyright (c) 2013, Swedish Institute of Computer Science
3  * Copyright (c) 2010, Vrije Universiteit Brussel
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the Institute nor the names of its contributors
15  * may be used to endorse or promote products derived from this software
16  * without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  *
31  * Authors: Simon Duquennoy <simonduq@sics.se>
32  * Joris Borms <joris.borms@vub.ac.be>
33  */
34 
35 #include "contiki.h"
36 
37 #include <stddef.h>
38 #include <string.h>
39 #include "lib/memb.h"
40 #include "lib/list.h"
41 #include "net/nbr-table.h"
42 
43 /* List of link-layer addresses of the neighbors, used as key in the tables */
44 typedef struct nbr_table_key {
45  struct nbr_table_key *next;
46  linkaddr_t lladdr;
47 } nbr_table_key_t;
48 
49 /* For each neighbor, a map of the tables that use the neighbor.
50  * As we are using uint8_t, we have a maximum of 8 tables in the system */
51 static uint8_t used_map[NBR_TABLE_MAX_NEIGHBORS];
52 /* For each neighbor, a map of the tables that lock the neighbor */
53 static uint8_t locked_map[NBR_TABLE_MAX_NEIGHBORS];
54 /* The maximum number of tables */
55 #define MAX_NUM_TABLES 8
56 /* A list of pointers to tables in use */
57 static struct nbr_table *all_tables[MAX_NUM_TABLES];
58 /* The current number of tables */
59 static unsigned num_tables;
60 
61 /* The neighbor address table */
62 MEMB(neighbor_addr_mem, nbr_table_key_t, NBR_TABLE_MAX_NEIGHBORS);
63 LIST(nbr_table_keys);
64 
65 /*---------------------------------------------------------------------------*/
66 /* Get a key from a neighbor index */
67 static nbr_table_key_t *
68 key_from_index(int index)
69 {
70  return index != -1 ? &((nbr_table_key_t *)neighbor_addr_mem.mem)[index] : NULL;
71 }
72 /*---------------------------------------------------------------------------*/
73 /* Get an item from its neighbor index */
74 static nbr_table_item_t *
75 item_from_index(nbr_table_t *table, int index)
76 {
77  return table != NULL && index != -1 ? (char *)table->data + index * table->item_size : NULL;
78 }
79 /*---------------------------------------------------------------------------*/
80 /* Get the neighbor index of an item */
81 static int
82 index_from_key(nbr_table_key_t *key)
83 {
84  return key != NULL ? key - (nbr_table_key_t *)neighbor_addr_mem.mem : -1;
85 }
86 /*---------------------------------------------------------------------------*/
87 /* Get the neighbor index of an item */
88 static int
89 index_from_item(nbr_table_t *table, const nbr_table_item_t *item)
90 {
91  return table != NULL && item != NULL ? ((int)((char *)item - (char *)table->data)) / table->item_size : -1;
92 }
93 /*---------------------------------------------------------------------------*/
94 /* Get an item from its key */
95 static nbr_table_item_t *
96 item_from_key(nbr_table_t *table, nbr_table_key_t *key)
97 {
98  return item_from_index(table, index_from_key(key));
99 }
100 /*---------------------------------------------------------------------------*/
101 /* Get the key af an item */
102 static nbr_table_key_t *
103 key_from_item(nbr_table_t *table, const nbr_table_item_t *item)
104 {
105  return key_from_index(index_from_item(table, item));
106 }
107 /*---------------------------------------------------------------------------*/
108 /* Get the index of a neighbor from its link-layer address */
109 static int
110 index_from_lladdr(const linkaddr_t *lladdr)
111 {
112  nbr_table_key_t *key;
113  /* Allow lladdr-free insertion, useful e.g. for IPv6 ND.
114  * Only one such entry is possible at a time, indexed by linkaddr_null. */
115  if(lladdr == NULL) {
116  lladdr = &linkaddr_null;
117  }
118  key = list_head(nbr_table_keys);
119  while(key != NULL) {
120  if(lladdr && linkaddr_cmp(lladdr, &key->lladdr)) {
121  return index_from_key(key);
122  }
123  key = list_item_next(key);
124  }
125  return -1;
126 }
127 /*---------------------------------------------------------------------------*/
128 /* Get bit from "used" or "locked" bitmap */
129 static int
130 nbr_get_bit(uint8_t *bitmap, nbr_table_t *table, nbr_table_item_t *item)
131 {
132  int item_index = index_from_item(table, item);
133  if(table != NULL && item_index != -1) {
134  return (bitmap[item_index] & (1 << table->index)) != 0;
135  } else {
136  return 0;
137  }
138  return 0;
139 }
140 /*---------------------------------------------------------------------------*/
141 /* Set bit in "used" or "locked" bitmap */
142 static int
143 nbr_set_bit(uint8_t *bitmap, nbr_table_t *table, nbr_table_item_t *item, int value)
144 {
145  int item_index = index_from_item(table, item);
146  if(table != NULL && item_index != -1) {
147  if(value) {
148  bitmap[item_index] |= 1 << table->index;
149  } else {
150  bitmap[item_index] &= ~(1 << table->index);
151  }
152  return 1;
153  } else {
154  return 0;
155  }
156  return 0;
157 }
158 /*---------------------------------------------------------------------------*/
159 static nbr_table_key_t *
160 nbr_table_allocate(void)
161 {
162  nbr_table_key_t *key;
163  int least_used_count = 0;
164  nbr_table_key_t *least_used_key = NULL;
165 
166  key = memb_alloc(&neighbor_addr_mem);
167  if(key != NULL) {
168  return key;
169  } else { /* No more space, try to free a neighbor.
170  * The replacement policy is the following: remove neighbor that is:
171  * (1) not locked
172  * (2) used by fewest tables
173  * (3) oldest (the list is ordered by insertion time)
174  * */
175  /* Get item from first key */
176  key = list_head(nbr_table_keys);
177  while(key != NULL) {
178  int item_index = index_from_key(key);
179  int locked = locked_map[item_index];
180  /* Never delete a locked item */
181  if(!locked) {
182  int used = used_map[item_index];
183  int used_count = 0;
184  /* Count how many tables are using this item */
185  while(used != 0) {
186  if((used & 1) == 1) {
187  used_count++;
188  }
189  used >>= 1;
190  }
191  /* Find least used item */
192  if(least_used_key == NULL || used_count < least_used_count) {
193  least_used_key = key;
194  least_used_count = used_count;
195  if(used_count == 0) { /* We won't find any least used item */
196  break;
197  }
198  }
199  }
200  key = list_item_next(key);
201  }
202  if(least_used_key == NULL) {
203  /* We haven't found any unlocked item, allocation fails */
204  return NULL;
205  } else {
206  /* Reuse least used item */
207  int i;
208  for(i = 0; i<MAX_NUM_TABLES; i++) {
209  if(all_tables[i] != NULL && all_tables[i]->callback != NULL) {
210  /* Call table callback for each table that uses this item */
211  nbr_table_item_t *removed_item = item_from_key(all_tables[i], least_used_key);
212  if(nbr_get_bit(used_map, all_tables[i], removed_item) == 1) {
213  all_tables[i]->callback(removed_item);
214  }
215  }
216  }
217  /* Empty used map */
218  used_map[index_from_key(least_used_key)] = 0;
219  /* Remove neighbor from list */
220  list_remove(nbr_table_keys, least_used_key);
221  /* Return associated key */
222  return least_used_key;
223  }
224  }
225 }
226 /*---------------------------------------------------------------------------*/
227 /* Register a new neighbor table. To be used at initialization by modules
228  * using a neighbor table */
229 int
230 nbr_table_register(nbr_table_t *table, nbr_table_callback *callback)
231 {
232  if(num_tables < MAX_NUM_TABLES) {
233  table->index = num_tables++;
234  table->callback = callback;
235  all_tables[table->index] = table;
236  return 1;
237  } else {
238  /* Maximum number of tables exceeded */
239  return 0;
240  }
241 }
242 /*---------------------------------------------------------------------------*/
243 /* Returns the first item of the current table */
244 nbr_table_item_t *
245 nbr_table_head(nbr_table_t *table)
246 {
247  /* Get item from first key */
248  nbr_table_item_t *item = item_from_key(table, list_head(nbr_table_keys));
249  /* Item is the first neighbor, now check is it is in the current table */
250  if(nbr_get_bit(used_map, table, item)) {
251  return item;
252  } else {
253  return nbr_table_next(table, item);
254  }
255 }
256 /*---------------------------------------------------------------------------*/
257 /* Iterates over the current table */
258 nbr_table_item_t *
259 nbr_table_next(nbr_table_t *table, nbr_table_item_t *item)
260 {
261  do {
262  void *key = key_from_item(table, item);
263  key = list_item_next(key);
264  /* Loop until the next item is in the current table */
265  item = item_from_key(table, key);
266  } while(item && !nbr_get_bit(used_map, table, item));
267  return item;
268 }
269 /*---------------------------------------------------------------------------*/
270 /* Add a neighbor indexed with its link-layer address */
271 nbr_table_item_t *
272 nbr_table_add_lladdr(nbr_table_t *table, const linkaddr_t *lladdr)
273 {
274  int index;
275  nbr_table_item_t *item;
276  nbr_table_key_t *key;
277 
278  /* Allow lladdr-free insertion, useful e.g. for IPv6 ND.
279  * Only one such entry is possible at a time, indexed by linkaddr_null. */
280  if(lladdr == NULL) {
281  lladdr = &linkaddr_null;
282  }
283 
284  if((index = index_from_lladdr(lladdr)) == -1) {
285  /* Neighbor not yet in table, let's try to allocate one */
286  key = nbr_table_allocate();
287 
288  /* No space available for new entry */
289  if(key == NULL) {
290  return NULL;
291  }
292 
293  /* Add neighbor to list */
294  list_add(nbr_table_keys, key);
295 
296  /* Get index from newly allocated neighbor */
297  index = index_from_key(key);
298 
299  /* Set link-layer address */
300  linkaddr_copy(&key->lladdr, lladdr);
301  }
302 
303  /* Get item in the current table */
304  item = item_from_index(table, index);
305 
306  /* Initialize item data and set "used" bit */
307  memset(item, 0, table->item_size);
308  nbr_set_bit(used_map, table, item, 1);
309 
310  return item;
311 }
312 /*---------------------------------------------------------------------------*/
313 /* Get an item from its link-layer address */
314 void *
315 nbr_table_get_from_lladdr(nbr_table_t *table, const linkaddr_t *lladdr)
316 {
317  void *item = item_from_index(table, index_from_lladdr(lladdr));
318  return nbr_get_bit(used_map, table, item) ? item : NULL;
319 }
320 /*---------------------------------------------------------------------------*/
321 /* Removes a neighbor from the current table (unset "used" bit) */
322 int
323 nbr_table_remove(nbr_table_t *table, void *item)
324 {
325  int ret = nbr_set_bit(used_map, table, item, 0);
326  nbr_set_bit(locked_map, table, item, 0);
327  return ret;
328 }
329 /*---------------------------------------------------------------------------*/
330 /* Lock a neighbor for the current table (set "locked" bit) */
331 int
332 nbr_table_lock(nbr_table_t *table, void *item)
333 {
334  return nbr_set_bit(locked_map, table, item, 1);
335 }
336 /*---------------------------------------------------------------------------*/
337 /* Release the lock on a neighbor for the current table (unset "locked" bit) */
338 int
339 nbr_table_unlock(nbr_table_t *table, void *item)
340 {
341  return nbr_set_bit(locked_map, table, item, 0);
342 }
343 /*---------------------------------------------------------------------------*/
344 /* Get link-layer address of an item */
345 linkaddr_t *
346 nbr_table_get_lladdr(nbr_table_t *table, const void *item)
347 {
348  nbr_table_key_t *key = key_from_item(table, item);
349  return key != NULL ? &key->lladdr : NULL;
350 }