From cfb3bbdad93bb29d8134b1fbf8a05ff7caaa9a97 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 3 Jul 2013 19:12:23 +0200 Subject: [PATCH] Added new neighbor-table module, a centralized place where to store all data about neighbors, indexed by link-layer address. Meant for use in other Contiki modules such as rpl, ds6, ds6-route, phase, neighbor-info. --- core/net/Makefile.uip | 1 + core/net/neighbor-table.c | 350 ++++++++++++++++++++++++++++++++++++++ core/net/neighbor-table.h | 103 +++++++++++ 3 files changed, 454 insertions(+) create mode 100644 core/net/neighbor-table.c create mode 100644 core/net/neighbor-table.h diff --git a/core/net/Makefile.uip b/core/net/Makefile.uip index 469a29b22..c675bfe74 100644 --- a/core/net/Makefile.uip +++ b/core/net/Makefile.uip @@ -3,6 +3,7 @@ dhcpc.c \ hc.c \ neighbor-attr.c \ neighbor-info.c \ +neighbor-table.c \ netstack.c \ packetbuf.c \ packetqueue.c \ diff --git a/core/net/neighbor-table.c b/core/net/neighbor-table.c new file mode 100644 index 000000000..194e996d5 --- /dev/null +++ b/core/net/neighbor-table.c @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2013, Swedish Institute of Computer Science + * Copyright (c) 2010, Vrije Universiteit Brussel + * 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 Institute 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 INSTITUTE 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 INSTITUTE OR CONTRIBUTORS 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. + * + * + * Authors: Simon Duquennoy + * Joris Borms + */ + +#include "contiki.h" + +#include +#include +#include "lib/memb.h" +#include "lib/list.h" +#include "net/neighbor-table.h" + +/* List of link-layer addresses of the neighbors, used as key in the tables */ +typedef struct nbr_table_key { + struct nbr_table_key *next; + rimeaddr_t lladdr; +} nbr_table_key_t; + +/* For each neighbor, a map of the tables that use the neighbor. + * As we are using uint8_t, we have a maximum of 8 tables in the system */ +static uint8_t used_map[NEIGHBOR_TABLE_MAX_NEIGHBORS]; +/* For each neighbor, a map of the tables that lock the neighbor */ +static uint8_t locked_map[NEIGHBOR_TABLE_MAX_NEIGHBORS]; +/* The maximum number of tables */ +#define MAX_NUM_TABLES 8 +/* A list of pointers to tables in use */ +static struct nbr_table *all_tables[MAX_NUM_TABLES]; +/* The current number of tables */ +static unsigned num_tables; + +/* The neighbor address table */ +MEMB(neighbor_addr_mem, nbr_table_key_t, NEIGHBOR_TABLE_MAX_NEIGHBORS); +LIST(nbr_table_keys); + +/*---------------------------------------------------------------------------*/ +/* Get a key from a neighbor index */ +static nbr_table_key_t * +key_from_index(int index) +{ + return index != -1 ? &((nbr_table_key_t *)neighbor_addr_mem.mem)[index] : NULL; +} +/*---------------------------------------------------------------------------*/ +/* Get an item from its neighbor index */ +static item_t * +item_from_index(nbr_table_t *table, int index) +{ + return table != NULL && index != -1 ? (char *)table->data + index * table->item_size : NULL; +} +/*---------------------------------------------------------------------------*/ +/* Get the neighbor index of an item */ +static int +index_from_key(nbr_table_key_t *key) +{ + return key != NULL ? key - (nbr_table_key_t *)neighbor_addr_mem.mem : -1; +} +/*---------------------------------------------------------------------------*/ +/* Get the neighbor index of an item */ +static int +index_from_item(nbr_table_t *table, item_t *item) +{ + return table != NULL && item != NULL ? ((int)((char *)item - (char *)table->data)) / table->item_size : -1; +} +/*---------------------------------------------------------------------------*/ +/* Get an item from its key */ +static item_t * +item_from_key(nbr_table_t *table, nbr_table_key_t *key) +{ + return item_from_index(table, index_from_key(key)); +} +/*---------------------------------------------------------------------------*/ +/* Get the key af an item */ +static nbr_table_key_t * +key_from_item(nbr_table_t *table, item_t *item) +{ + return key_from_index(index_from_item(table, item)); +} +/*---------------------------------------------------------------------------*/ +/* Get the index of a neighbor from its link-layer address */ +static int +index_from_lladdr(const rimeaddr_t *lladdr) +{ + nbr_table_key_t *key; + /* Allow lladdr-free insertion, useful e.g. for IPv6 ND. + * Only one such entry is possible at a time, indexed by rimeaddr_null. */ + if(lladdr == NULL) { + lladdr = &rimeaddr_null; + } + key = list_head(nbr_table_keys); + while(key != NULL) { + if(lladdr && rimeaddr_cmp(lladdr, &key->lladdr)) { + return index_from_key(key); + } + key = list_item_next(key); + } + return -1; +} +/*---------------------------------------------------------------------------*/ +/* Get bit from "used" or "locked" bitmap */ +static int +nbr_get_bit(uint8_t *bitmap, nbr_table_t *table, item_t *item) +{ + int item_index = index_from_item(table, item); + if(table != NULL && item_index != -1) { + return (bitmap[item_index] & (1 << table->index)) != 0; + } else { + return 0; + } + return 0; +} +/*---------------------------------------------------------------------------*/ +/* Set bit in "used" or "locked" bitmap */ +static int +nbr_set_bit(uint8_t *bitmap, nbr_table_t *table, item_t *item, int value) +{ + int item_index = index_from_item(table, item); + if(table != NULL && item_index != -1) { + if(value) { + bitmap[item_index] |= 1 << table->index; + } else { + bitmap[item_index] &= ~(1 << table->index); + } + return 1; + } else { + return 0; + } + return 0; +} +/*---------------------------------------------------------------------------*/ +static nbr_table_key_t * +nbr_table_allocate() +{ + nbr_table_key_t *key; + int least_used_count = 0; + nbr_table_key_t *least_used_key = NULL; + + key = memb_alloc(&neighbor_addr_mem); + if(key != NULL) { + return key; + } else { /* No more space, try to free a neighbor. + * The replacement policy is the following: remove neighbor that is: + * (1) not locked + * (2) used by fewest tables + * (3) oldest (the list is ordered by insertion time) + * */ + /* Get item from first key */ + key = list_head(nbr_table_keys); + while(key != NULL) { + int item_index = index_from_key(key); + int locked = locked_map[item_index]; + /* Never delete a locked item */ + if(!locked) { + int used = used_map[item_index]; + int used_count = 0; + /* Count how many tables are using this item */ + while(used != 0) { + if((used & 1) == 1) { + used_count++; + } + used >>= 1; + } + /* Find least used item */ + if(least_used_key == NULL || used_count < least_used_count) { + least_used_key = key; + least_used_count = used_count; + if(used_count == 0) { /* We won't find any least used item */ + break; + } + } + } + key = list_item_next(key); + } + if(least_used_key == NULL) { + /* We haven't found any unlocked item, allocation fails */ + return NULL; + } else { + /* Reuse least used item */ + int i; + for(i = 0; icallback != NULL) { + /* Call table callback for each table that uses this item */ + item_t *removed_item = item_from_key(all_tables[i], least_used_key); + if(nbr_get_bit(used_map, all_tables[i], removed_item) == 1) { + all_tables[i]->callback(removed_item); + } + } + } + /* Empty used map */ + used_map[index_from_key(least_used_key)] = 0; + /* Remove neighbor from list */ + list_remove(nbr_table_keys, least_used_key); + /* Return associated key */ + return least_used_key; + } + } +} +/*---------------------------------------------------------------------------*/ +/* Register a new neighbor table. To be used at initialization by modules + * using a neighbor table */ +int +nbr_table_register(nbr_table_t *table, remove_callback_func *callback) +{ + if(num_tables < MAX_NUM_TABLES) { + table->index = num_tables++; + table->callback = callback; + all_tables[table->index] = table; + return 1; + } else { + /* Maximum number of tables exceeded */ + return 0; + } +} +/*---------------------------------------------------------------------------*/ +/* Returns the first item of the current table */ +item_t * +nbr_table_head(nbr_table_t *table) +{ + /* Get item from first key */ + item_t *item = item_from_key(table, list_head(nbr_table_keys)); + /* Item is the first neighbor, now check is it is in the current table */ + if(nbr_get_bit(used_map, table, item)) { + return item; + } else { + return nbr_table_next(table, item); + } +} +/*---------------------------------------------------------------------------*/ +/* Iterates over the current table */ +item_t * +nbr_table_next(nbr_table_t *table, item_t *item) +{ + do { + void *key = key_from_item(table, item); + key = list_item_next(key); + /* Loop until the next item is in the current table */ + item = item_from_key(table, key); + } while(item && !nbr_get_bit(used_map, table, item)); + return item; +} +/*---------------------------------------------------------------------------*/ +/* Add a neighbor indexed with its link-layer address */ +item_t * +nbr_table_add_lladdr(nbr_table_t *table, const rimeaddr_t *lladdr) +{ + int index; + item_t *item; + nbr_table_key_t *key; + + /* Allow lladdr-free insertion, useful e.g. for IPv6 ND. + * Only one such entry is possible at a time, indexed by rimeaddr_null. */ + if(lladdr == NULL) { + lladdr = &rimeaddr_null; + } + + if((index = index_from_lladdr(lladdr)) == -1) { + /* Neighbor not yet in table, let's try to allocate one */ + key = nbr_table_allocate(); + + /* No space available for new entry */ + if(key == NULL) { + return NULL; + } + + /* Add neighbor to list */ + list_add(nbr_table_keys, key); + + /* Get index from newly allocated neighbor */ + index = index_from_key(key); + + /* Set link-layer address */ + rimeaddr_copy(&key->lladdr, lladdr); + } + + /* Get item in the current table */ + item = item_from_index(table, index); + + /* Initialize item data and set "used" bit */ + memset(item, 0, table->item_size); + nbr_set_bit(used_map, table, item, 1); + + return item; +} +/*---------------------------------------------------------------------------*/ +/* Get an item from its link-layer address */ +void * +nbr_table_get_from_lladdr(nbr_table_t *table, const rimeaddr_t *lladdr) +{ + void *item = item_from_index(table, index_from_lladdr(lladdr)); + return nbr_get_bit(used_map, table, item) ? item : NULL; +} +/*---------------------------------------------------------------------------*/ +/* Removes a neighbor from the current table (unset "used" bit) */ +int +nbr_table_remove(nbr_table_t *table, void *item) +{ + int ret = nbr_set_bit(used_map, table, item, 0); + nbr_set_bit(locked_map, table, item, 0); + return ret; +} +/*---------------------------------------------------------------------------*/ +/* Lock a neighbor for the current table (set "locked" bit) */ +int +nbr_table_lock(nbr_table_t *table, void *item) +{ + return nbr_set_bit(locked_map, table, item, 1); +} +/*---------------------------------------------------------------------------*/ +/* Release the lock on a neighbor for the current table (unset "locked" bit) */ +int +nbr_table_unlock(nbr_table_t *table, void *item) +{ + return nbr_set_bit(locked_map, table, item, 0); +} +/*---------------------------------------------------------------------------*/ +/* Get link-layer address of an item */ +rimeaddr_t * +nbr_table_get_lladdr(nbr_table_t *table, void *item) +{ + nbr_table_key_t *key = key_from_item(table, item); + return key != NULL ? &key->lladdr : NULL; +} diff --git a/core/net/neighbor-table.h b/core/net/neighbor-table.h new file mode 100644 index 000000000..f2b2f8034 --- /dev/null +++ b/core/net/neighbor-table.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2013, Swedish Institute of Computer Science + * Copyright (c) 2010, Vrije Universiteit Brussel + * 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 Institute 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 INSTITUTE 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 INSTITUTE OR CONTRIBUTORS 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. + * + * + * Authors: Simon Duquennoy + * Joris Borms + */ + +#ifndef _NEIGHBOR_TABLE_H_ +#define _NEIGHBOR_TABLE_H_ + +#include "contiki.h" +#include "net/rime/rimeaddr.h" +#include "net/netstack.h" + +/* Neighbor table size */ +#ifdef NEIGHBOR_CONF_MAX_NEIGHBORS +#define NEIGHBOR_TABLE_MAX_NEIGHBORS NEIGHBOR_CONF_MAX_NEIGHBORS +#else /* NEIGHBOR_CONF_MAX_NEIGHBORS */ +#define NEIGHBOR_TABLE_MAX_NEIGHBORS 8 +#endif /* NEIGHBOR_CONF_MAX_NEIGHBORS */ + +/* An item in a neighbor table */ +typedef void item_t; + +/* Callback function, called when removing an item from a table */ +typedef void(remove_callback_func)(item_t *item); + +/* A neighbor table */ +typedef struct nbr_table { + int index; + int item_size; + remove_callback_func *callback; + item_t *data; +} nbr_table_t; + +/** \brief A static neighbor table. To be initialized through nbr_table_register(name) */ +#define NEIGHBOR_TABLE(type, name) \ + static type _##name##_mem[NEIGHBOR_TABLE_MAX_NEIGHBORS]; \ + static nbr_table_t name##_struct = { 0, sizeof(type), NULL, (item_t *)_##name##_mem }; \ + static nbr_table_t *name = &name##_struct \ + +/** \brief A non-static neighbor table. To be initialized through nbr_table_register(name) */ +#define NEIGHBOR_TABLE_GLOBAL(type, name) \ + static type _##name##_mem[NEIGHBOR_TABLE_MAX_NEIGHBORS]; \ + static nbr_table_t name##_struct = { 0, sizeof(type), NULL, (item_t *)_##name##_mem }; \ + nbr_table_t *name = &name##_struct \ + +/** \brief Declaration of non-static neighbor tables */ +#define NEIGHBOR_TABLE_DECLARE(name) extern nbr_table_t *name + +/** \name Neighbor tables: register and loop through table elements */ +/** @{ */ +int nbr_table_register(nbr_table_t *table, remove_callback_func *callback); +item_t *nbr_table_head(nbr_table_t *table); +item_t *nbr_table_next(nbr_table_t *table, item_t *item); +/** @} */ + +/** \name Neighbor tables: add and get data */ +/** @{ */ +item_t *nbr_table_add_lladdr(nbr_table_t *table, const rimeaddr_t *lladdr); +item_t *nbr_table_get_from_lladdr(nbr_table_t *table, const rimeaddr_t *lladdr); +/** @} */ + +/** \name Neighbor tables: set flags (unused, locked, unlocked) */ +/** @{ */ +int nbr_table_remove(nbr_table_t *table, item_t *item); +int nbr_table_lock(nbr_table_t *table, item_t *item); +int nbr_table_unlock(nbr_table_t *table, item_t *item); +/** @} */ + +/** \name Neighbor tables: address manipulation */ +/** @{ */ +rimeaddr_t *nbr_table_get_lladdr(nbr_table_t *table, item_t *item); +/** @} */ + +#endif /* _NEIGHBOR_TABLE_H_ */