/* Get the index of a neighbor from its link-layer address */
static int
index_from_lladdr(const linkaddr_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 linkaddr_null. */
    if(lladdr == NULL) {
        lladdr = &linkaddr_null;
    }
    key = list_head(nbr_table_keys);
    while(key != NULL) {
        if(lladdr && linkaddr_cmp(lladdr, &key->lladdr)) {
            return index_from_key(key);
        }
        key = list_item_next(key);
    }
    return -1;
}
Exemple #2
0
/*---------------------------------------------------------------------------*/
static void
remove_key(nbr_table_key_t *least_used_key)
{
  int i;
  for(i = 0; i < MAX_NUM_TABLES; i++) {
    if(all_tables[i] != NULL && all_tables[i]->callback != NULL) {
      /* Call table callback for each table that uses this item */
      nbr_table_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);
}
/* Get an item from its key */
static nbr_table_item_t *
item_from_key(nbr_table_t *table, nbr_table_key_t *key)
{
    return item_from_index(table, index_from_key(key));
}
/*---------------------------------------------------------------------------*/
static nbr_table_key_t *
nbr_table_allocate(void)
{
    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; i<MAX_NUM_TABLES; i++) {
                if(all_tables[i] != NULL && all_tables[i]->callback != NULL) {
                    /* Call table callback for each table that uses this item */
                    nbr_table_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;
        }
    }
Exemple #5
0
/*---------------------------------------------------------------------------*/
static nbr_table_key_t *
nbr_table_allocate(nbr_table_reason_t reason, void *data)
{
  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 {
#ifdef NBR_TABLE_FIND_REMOVABLE
    const linkaddr_t *lladdr;
    lladdr = NBR_TABLE_FIND_REMOVABLE(reason, data);
    if(lladdr == NULL) {
      /* Nothing found that can be deleted - return NULL to indicate failure */
      PRINTF("*** Not removing entry to allocate new\n");
      return NULL;
    } else {
      /* used least_used_key to indicate what is the least useful entry */
      int index;
      int locked = 0;
      if((index = index_from_lladdr(lladdr)) != -1) {
        least_used_key = key_from_index(index);
        locked = locked_map[index];
      }
      /* Allow delete of locked item? */
      if(least_used_key != NULL && locked) {
        PRINTF("Deleting locked item!\n");
        locked_map[index] = 0;
      }
    }
#endif /* NBR_TABLE_FIND_REMOVABLE */

    if(least_used_key == NULL) {
      /* 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);
      }
    }