---
 helper/Makefile.am                    |   5 +-
 helper/include/odp/helper/odp_table.h | 184 ++++++++++++++++++
 helper/odp_hashtable.c                | 342 ++++++++++++++++++++++++++++++++++
 helper/odp_hashtable.h                |  37 ++++
 helper/odp_lineartable.c              | 210 +++++++++++++++++++++
 helper/odp_lineartable.h              |  37 ++++
 helper/odp_list_internal.h            |  82 ++++++++
 helper/test/Makefile.am               |   5 +-
 helper/test/odp_table_test.c          | 119 ++++++++++++
 9 files changed, 1019 insertions(+), 2 deletions(-)
 mode change 100644 => 100755 helper/Makefile.am
 create mode 100755 helper/include/odp/helper/odp_table.h
 create mode 100755 helper/odp_hashtable.c
 create mode 100755 helper/odp_hashtable.h
 create mode 100755 helper/odp_lineartable.c
 create mode 100755 helper/odp_lineartable.h
 create mode 100755 helper/odp_list_internal.h
 mode change 100644 => 100755 helper/test/Makefile.am
 create mode 100755 helper/test/odp_table_test.c

diff --git a/helper/Makefile.am b/helper/Makefile.am
old mode 100644
new mode 100755
index 1a74e8e..32a6184
--- a/helper/Makefile.am
+++ b/helper/Makefile.am
@@ -17,6 +17,7 @@ helperinclude_HEADERS = \
                  $(srcdir)/include/odp/helper/ip.h\
                  $(srcdir)/include/odp/helper/ipsec.h\
                  $(srcdir)/include/odp/helper/tcp.h\
+                 $(srcdir)/include/odp/helper/odp_table.h\
                  $(srcdir)/include/odp/helper/udp.h
 
 noinst_HEADERS = \
@@ -25,6 +26,8 @@ noinst_HEADERS = \
 
 __LIB__libodphelper_la_SOURCES = \
                                        linux.c \
-                                       ring.c
+                                       ring.c \
+                                       odp_hashtable.c \
+                                       odp_lineartable.c
 
 lib_LTLIBRARIES = $(LIB)/libodphelper.la
diff --git a/helper/include/odp/helper/odp_table.h 
b/helper/include/odp/helper/odp_table.h
new file mode 100755
index 0000000..3e9c5ab
--- /dev/null
+++ b/helper/include/odp/helper/odp_table.h
@@ -0,0 +1,184 @@
+/* Copyright (c) 2014, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2013 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS 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 COPYRIGHT
+ *   OWNER 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.
+ */
+
+/**
+ * @file
+ *
+ * ODP table
+ *
+ * This tool is part of ODP helper suite, designed to provide a standard 
interface 
+ * to implement different types of tables for data processing.
+ * Use case:
+ * Table is publicly used in the following scenarios in data plane: 
+ * ARP Table, IP Routing Table, MAC address filtering, ACL, interworking etc.
+ * The features of the "table":
+ * 1) All these different types of "table" have the common operations:
+ *    Create a table, destroy a table, add an entry (key/value pairs), delete 
an entry, and lookup the value via the key. 
+ *    Usually these operations are software based, but also can be hardware 
accelerated if cost, 
+ *    power consumption are not the concern in your platform.   
+ * 2) Different types of "table" can use different algorithms to 
add/delete/lookup the entry. 
+ * 
+ */
+
+#ifndef ODP_TABLE_H_
+#define ODP_TABLE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ODP_TABLE_NAME_LEN      32
+
+typedef ODP_HANDLE_T(odp_table_t);
+
+/**
+* create a table
+* Generally, we suppose Tables only support key-value pair both with fixed size
+*
+* @param name
+*    name of this table, max ODP_TABLE_NAME_LEN - 1
+*    May be specified as NULL for anonymous table
+* @param capacity
+*    Max memory usage this table use, in MBytes(for memory allocation purpose)
+* @param key_size
+*    fixed size of the 'key' in bytes. 
+* @param value_size
+*    fixed size of the 'value' in bytes.
+* @return
+*   Handle to table instance or NULL if failed
+* @note 
+*/
+typedef odp_table_t (*odp_table_create)(const char *name, uint32_t capacity, 
uint32_t key_size, uint32_t value_size);
+
+/**
+ * Find a table by name
+ *
+ * @param name:      Name of the table
+ *
+ * @return Handle of found table
+ * @retval NULL  table could not be found
+ *
+ * @note 
+ *     This routine cannot be used to look up an anonymous table (one created 
with no name).
+ *     This API supports Multiprocess 
+ */
+typedef odp_table_t (*odp_table_lookup)(const char *name);
+
+/**
+ * Destroy a table previously created by odp_table_create()
+ *
+ * @param table: Handle of the table to be destroyed
+ *
+ * @retval 0 Success
+ * @retval -1 Failure
+ *
+ * @note 
+ *       This routine destroys a previously created pool
+ *       also should free any memory allocated at creation 
+ * 
+ */
+typedef int (*odp_table_destroy)(odp_table_t table);
+
+/**
+ * table element add
+ *
+ * @param table:    Handle of the table that the element be added
+ * 
+ * @param key : address of 'key' in key-value pair. 
+ *              User should make sure the address and 'key_size' bytes after 
are accessible
+ * @param value : address of 'value' in key-value pair
+ *              User should make sure the address and 'value_size' bytes after 
are accessible
+ * @retval 0 Success
+ * @retval -1 Failure
+ *
+ * @note: Add a same key again with a new value, the older value will be 
covered.
+ *        This API supports Multiprocess
+ */
+typedef int (*odp_table_put_value)(odp_table_t table,void* key,void *value);
+
+/**
+ * table element lookup
+ *
+ * @param table: Handle of the table that the element be added
+ * 
+ * @param key : address of 'key' in key-value pair
+ *              User should make sure the address and key_size bytes after are 
accessible
+ * 
+ * @param buffer : output The buffer address to the 'value'
+                   After successfully found, the content of 'value' will be 
copied to this address 
+ *                 User should make sure the address and value_size bytes 
after are accessible
+ * @param buffer_size: size of the buffer, should be equal or bigger than 
value_size
+
+ * @retval 0 Success
+ * @retval -1 Failure
+ *
+ * @note: This API supports Multiprocess 
+ */
+typedef int (*odp_table_get_value)(odp_table_t table,void* key,void *buffer, 
uint32_t buffer_size);
+
+
+/**
+ * table element remove
+ *
+ * @param table: Handle of the table that the element will be removed from
+ * 
+ * @param key : address of 'key' in key-value pair
+ *              User should make sure the address and key_size bytes after are 
accessible
+ * 
+ * @retval 0 Success
+ * @retval -1 Failure
+ *
+ * @note: This API supports Multiprocess 
+ */
+typedef int (*odp_table_remove_value)(odp_table_t table, void *key);
+
+struct odp_table_ops {
+    odp_table_create        f_create;       /* Table Create */
+    odp_table_lookup        f_lookup;       /* Table Lookup */
+    odp_table_destroy       f_des;          /* Table Destroy */
+    odp_table_put_value     f_put;          /* Value Put */
+    odp_table_get_value     f_get;          /* Value Get */
+    odp_table_remove_value  f_remove;       /* Value Remove */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
\ No newline at end of file
diff --git a/helper/odp_hashtable.c b/helper/odp_hashtable.c
new file mode 100755
index 0000000..0162e5b
--- /dev/null
+++ b/helper/odp_hashtable.c
@@ -0,0 +1,342 @@
+/* Copyright (c) 2013, Linaro Limited
+* All rights reserved.
+*
+* SPDX-License-Identifier:     BSD-3-Clause
+*/
+#include <stdio.h>
+#include <string.h>
+#include <malloc.h>
+
+#include "odp_hashtable.h"
+#include "odp_list_internal.h"
+#include "odph_debug.h"
+
+#include <odp.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define    ODP_SUCCESS       0
+#define    ODP_FAIL          -1
+
+#define    ODP_HASH_TABLE_MAGIC_WORD   0xABABBABA
+#define    ODP_MAX_BUCKET_NUM          0x10000  /* 64k */
+
+/* inner element structure of hash table */
+typedef struct odp_hash_node{
+    list_object    list_node;       //list structure
+    char           content[0];      //Flexible Array,memory will be alloced 
when table has been created
+                                    //Its length is key_size+value_size, 
suppose key_size = m; value_size = n;
+                                    // its structure is like:
+                                    // key_byte1 key_byte2 
key_byte3...key_byten value_byte1...value_bytem
+} odp_hash_node;
+
+typedef struct{
+    uint32_t         magicword;             //for check
+    odp_rwlock_t    *lock_pool;             //multi-process support,every list 
has one rw lock
+    list_head       *list_head_pool;        //table bucket pool,every hash 
value has one list head
+                                            //To resolve the hash conflict
+    uint32_t         key_size;              
+    uint32_t         value_size;
+    uint32_t         head_num;                  //number of the list head in 
list_head_pool
+    uint32_t         init_cap;              
+    odp_hash_node   *hash_node_pool;            //table element pool
+    uint32_t         hash_node_num;             //number of element in the 
hash_node_pool
+    char             rsv[7];                    //for align
+    char             name[ODP_TABLE_NAME_LEN];  //table name
+} odp_hash_table_imp;
+
+//odp_hash_table_imp g_stGlobalHashTables[ODP_MAX_HASH_TABLE_NUM];
+
+
+odp_table_t odp_hash_table_create(const char *name, uint32_t capacity, 
uint32_t key_size, uint32_t value_size)
+{
+    int idx,i;
+    uint32_t node_num;
+    odp_hash_table_imp * hash_tbl;
+    odp_shm_t shmem;
+    uint32_t node_mem;
+    if(strlen(name) >= ODP_TABLE_NAME_LEN || capacity < 1 || capacity >= 
0x1000 || key_size == 0 || value_size == 0)
+    {
+        ODPH_DBG("create para input error!\n");
+        return NULL;
+    }
+    hash_tbl = (odp_hash_table_imp *)odp_shm_addr(odp_shm_lookup(name));
+    if(hash_tbl != NULL)
+    {
+        ODPH_DBG("name already exist\n");
+        return NULL;
+    }
+    shmem = odp_shm_reserve(name,capacity<<20,64,ODP_SHM_SW_ONLY);
+    if(shmem == ODP_SHM_INVALID)
+    {
+        ODPH_DBG("shm reserve fail\n");
+        return NULL;
+    }
+    hash_tbl = (odp_hash_table_imp *)odp_shm_addr(shmem);
+
+    /* clean this block of memory */
+    memset(hash_tbl,0,capacity<<20);
+    
+    hash_tbl->init_cap = capacity<<20;
+    strncpy(hash_tbl->name,name,ODP_TABLE_NAME_LEN);
+    hash_tbl->key_size = key_size;
+    hash_tbl->value_size = value_size;
+
+    /* header of this mem block is the table control struct, 
+     * then the lock pool, then the list header pool
+     * the last part is the element node pool
+     */
+
+    hash_tbl->lock_pool      = (odp_rwlock_t*)((char*)hash_tbl + 
sizeof(odp_hash_table_imp));
+    hash_tbl->list_head_pool = (list_head*)((char*)hash_tbl->lock_pool + 
ODP_MAX_BUCKET_NUM * sizeof(odp_rwlock_t));
+
+    node_mem = hash_tbl->init_cap - sizeof(odp_hash_table_imp) - 
ODP_MAX_BUCKET_NUM * (sizeof(list_head) + sizeof(odp_rwlock_t));
+    node_num = node_mem / (sizeof(odp_hash_node) + key_size + value_size);
+    hash_tbl->hash_node_num = node_num;
+    hash_tbl->hash_node_pool = (odp_hash_node 
*)((char*)hash_tbl->list_head_pool + ODP_MAX_BUCKET_NUM * sizeof(list_head));
+    
+    /* init every list head and rw lock */
+    for(i = 0;i < ODP_MAX_BUCKET_NUM;i++)
+    {
+        INIT_LIST_HEAD(&(hash_tbl->list_head_pool[i]));
+        odp_rwlock_init((odp_rwlock_t*)&(hash_tbl->lock_pool[i]));
+    }
+
+    /* finish */
+    hash_tbl->magicword = ODP_HASH_TABLE_MAGIC_WORD;
+    return (odp_table_t)hash_tbl;
+}
+
+int odp_hash_table_destroy(odp_table_t table)
+{
+    int ret;
+    if(table != NULL)
+    {
+        odp_hash_table_imp *hash_tbl = (odp_hash_table_imp*)table;
+        if(hash_tbl->magicword != ODP_HASH_TABLE_MAGIC_WORD)
+        {
+            return ODP_FAIL;
+        }
+        ret = odp_shm_free(odp_shm_lookup(hash_tbl->name));
+        if(ret != 0)
+        {
+            ODPH_DBG("free fail\n");
+            return ret;
+        }
+        /* clean head */
+        return ODP_SUCCESS;
+    }
+    return ODP_FAIL;
+}
+
+odp_table_t odp_hash_table_lookup(const char *name)
+{
+    int idx;
+    odp_hash_table_imp * hash_tbl;
+    if(name == NULL || strlen(name) >= ODP_TABLE_NAME_LEN)
+    {
+        return NULL;
+    }
+    hash_tbl = (odp_hash_table_imp *)odp_shm_addr(odp_shm_lookup(name));
+    if(hash_tbl != NULL && strcmp(hash_tbl->name,name) == 0)
+    {
+        return (odp_table_t)hash_tbl;
+    }
+    return NULL;
+}
+/*
+ * Calculate has value by the input key and key_size
+ * This hash algorithm is the most simple one, so we choose it as an DEMO
+ * User can use any other algorithm, like CRC...
+ */
+uint16_t odp_key_hash(void *key, uint32_t key_size)
+{
+    register uint32_t hash = 0;
+    uint32_t idx = (key_size == 0 ? 1:key_size);
+    uint32_t ch;
+
+    while(idx != 0)
+    {
+        ch = (uint32_t)(*(char*)key);
+        hash = hash * 131 + ch;
+        idx--;
+    }
+    return (uint16_t)(hash & 0x0000FFFF);
+}
+
+/*
+ * Get an available node from pool
+ */
+odp_hash_node * odp_hashnode_take(odp_table_t table)
+{
+    odp_hash_table_imp *hash_tbl = (odp_hash_table_imp*)table;
+    uint32_t idx;
+    odp_hash_node *pNode;
+    for(idx = 0; idx < hash_tbl->hash_node_num;idx++)
+    {
+        /* notice: memory of one hash_node is not only sizeof(odp_hash_node)
+         * should add the size of Flexible Array
+         */
+        pNode = (odp_hash_node *)((char*)hash_tbl->hash_node_pool 
+            + idx * (sizeof(odp_hash_node) + hash_tbl->key_size + 
hash_tbl->value_size));
+        if(pNode->list_node.next == NULL
+            &&pNode->list_node.prev == NULL)
+        {
+            INIT_LIST_HEAD(&(pNode->list_node));
+            return pNode;
+        }
+    }
+    return NULL;
+}
+/*
+ * Release an node to the pool
+ */
+void odp_hashnode_give(odp_table_t table, odp_hash_node *node)
+{
+    odp_hash_table_imp *hash_tbl = (odp_hash_table_imp*)table;
+    if(node == NULL)
+    {
+        return;
+    }
+    list_del(&node->list_node);
+    memset(node,0,(sizeof(odp_hash_node) + hash_tbl->key_size + 
hash_tbl->value_size));
+}
+
+/* should make sure the input table exists and is available */
+int odp_hash_put_value(odp_table_t table, void *key, void *value)
+{
+    odp_hash_table_imp *hash_tbl = (odp_hash_table_imp*)table;
+    uint16_t hash = 0;
+    odp_hash_node *node = NULL;
+    char* tmp = NULL;
+    if(table == NULL || key == NULL || value == NULL)
+    {
+        return ODP_FAIL;
+    }
+
+    /* hash value is just the index of the list head in pool */
+    hash = odp_key_hash(key, hash_tbl->key_size);
+
+    odp_rwlock_write_lock(&hash_tbl->lock_pool[hash]);
+    /* First, check if the key already exist */
+    LIST_FOR_EACH(node,&hash_tbl->list_head_pool[hash],odp_hash_node,list_node)
+    {
+        if(memcmp(node->content,key,hash_tbl->key_size) == 0)
+        {
+            /* copy value content to hash node*/
+            tmp = (void*)((char*)node->content + hash_tbl->key_size);
+            memcpy(tmp,value,hash_tbl->value_size);
+            
+            odp_rwlock_write_unlock(&hash_tbl->lock_pool[hash]);
+            
+            return ODP_SUCCESS;
+        }
+    }
+
+    /*if the key is a new one, get hash node form the pool */
+    node = odp_hashnode_take(table);
+    if(node == NULL)
+    {
+        odp_rwlock_write_unlock(&hash_tbl->lock_pool[hash]);
+        return ODP_FAIL;
+    }
+
+    /* copy both key and value content to the hash node */
+    memcpy(node->content,key,hash_tbl->key_size);
+    tmp = (void*)((char*)node->content + hash_tbl->key_size);
+    memcpy(tmp,value,hash_tbl->value_size);
+
+    /* add the node to list */
+    list_add(&node->list_node,&hash_tbl->list_head_pool[hash]);
+    
+    odp_rwlock_write_unlock(&hash_tbl->lock_pool[hash]);
+    return ODP_SUCCESS;
+}
+
+/* should make sure the input table exists and is available */
+int odp_hash_get_value(odp_table_t table, void *key, void *buffer, uint32_t 
buffer_size)
+{
+    odp_hash_table_imp *hash_tbl = (odp_hash_table_imp*)table;
+    uint16_t hash = 0;
+    odp_hash_node *node;
+    char* tmp = NULL;
+
+    if(table == NULL || key == NULL || buffer == NULL || buffer_size < 
hash_tbl->value_size)
+    {
+        return ODP_FAIL;
+    }
+
+    /* hash value is just the index of the list head in pool */
+    hash = odp_key_hash(key, hash_tbl->key_size);
+
+    odp_rwlock_read_lock(&hash_tbl->lock_pool[hash]);
+    
+    LIST_FOR_EACH(node,&hash_tbl->list_head_pool[hash],odp_hash_node,list_node)
+    {
+        /* in case of hash conflict, compare the whole key */
+        if(memcmp(node->content,key,hash_tbl->key_size) == 0)
+        {
+            /* find the target */
+            tmp = (void*)((char*)node->content + hash_tbl->key_size);
+            memcpy(buffer,tmp,hash_tbl->value_size);
+
+            odp_rwlock_read_unlock(&hash_tbl->lock_pool[hash]);
+            
+            return ODP_SUCCESS;
+        }
+    }
+
+    odp_rwlock_read_unlock(&hash_tbl->lock_pool[hash]);
+    
+    return ODP_FAIL;
+}
+
+/* should make sure the input table exists and is available */
+int odp_hash_remove_value(odp_table_t table, void *key)
+{
+    odp_hash_table_imp *hash_tbl = (odp_hash_table_imp*)table;
+    uint16_t hash = 0;
+    odp_hash_node *node;
+    if(table == NULL || key == NULL)
+    {
+        return ODP_FAIL;
+    }
+
+    /* hash value is just the index of the list head in pool */
+    hash = odp_key_hash(key, hash_tbl->key_size);
+
+    odp_rwlock_write_lock(&hash_tbl->lock_pool[hash]);
+    
+    LIST_FOR_EACH(node,&hash_tbl->list_head_pool[hash],odp_hash_node,list_node)
+    {
+        if(memcmp(node->content,key,hash_tbl->key_size) == 0)
+        {
+            odp_hashnode_give(table,node);
+
+            odp_rwlock_write_unlock(&hash_tbl->lock_pool[hash]);
+            
+            return ODP_SUCCESS;
+        }
+    }
+
+    odp_rwlock_write_unlock(&hash_tbl->lock_pool[hash]);
+    
+    return ODP_SUCCESS;
+}
+
+
+struct odp_table_ops odp_hash_table_ops = 
+{
+    odp_hash_table_create,
+    odp_hash_table_lookup,
+    odp_hash_table_destroy,
+    odp_hash_put_value,
+    odp_hash_get_value,
+    odp_hash_remove_value,
+};
+
+#ifdef __cplusplus
+}
+#endif
\ No newline at end of file
diff --git a/helper/odp_hashtable.h b/helper/odp_hashtable.h
new file mode 100755
index 0000000..f513e3e
--- /dev/null
+++ b/helper/odp_hashtable.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 2014, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+
+/**
+ * @file
+ *
+ * ODP Hash table
+ */
+
+#ifndef ODP_HASH_TABLE_H_
+#define ODP_HASH_TABLE_H_
+
+#include <stdint.h>
+#include <odp/plat/strong_types.h>
+#include <odp/helper/odp_table.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    extern odp_table_t odp_hash_table_create(const char *name, uint32_t 
capacity, uint32_t key_size,uint32_t value_size);
+    extern odp_table_t odp_hash_table_lookup(const char *name);
+    extern int   odp_hash_table_destroy(odp_table_t table);
+    extern int   odp_hash_put_value(odp_table_t table, void *key, void *value);
+    extern int   odp_hash_get_value(odp_table_t table, void *key, void  
*buffer, uint32_t buffer_size);
+    extern int   odp_hash_remove_value(odp_table_t table, void *key);
+
+    extern struct odp_table_ops odp_hash_table_ops;
+#ifdef __cplusplus
+}
+#endif
+
+#endif
\ No newline at end of file
diff --git a/helper/odp_lineartable.c b/helper/odp_lineartable.c
new file mode 100755
index 0000000..98e72b0
--- /dev/null
+++ b/helper/odp_lineartable.c
@@ -0,0 +1,210 @@
+/* Copyright (c) 2013, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <malloc.h>
+
+#include "odp_lineartable.h"
+#include "odph_debug.h"
+#include <odp.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define        ODP_SUCCESS            0
+#define     ODP_FAIL                     -1
+#define     ODP_LINEAR_TABLE_MAGIC_WORD   0xEFEFFEFE
+/* internal table struct  */
+typedef struct{
+    uint32_t        magicword;                  //for check
+    uint32_t        init_cap;                   //capacity
+    uint32_t        node_sum;                   //given the capacity,it shows 
how many nodes can we put into this table
+    uint32_t        value_size;                 //size of one linear table 
element, including the rwlock in the head
+    void            *data_array;                //node pool
+    char            name[ODP_TABLE_NAME_LEN];
+} odp_linear_table_imp;
+
+
+odp_table_t odp_linear_table_create(const char *name, uint32_t capacity, 
uint32_t key_size, uint32_t value_size)
+{
+    int idx;
+    uint32_t node_num;
+    odp_shm_t shmem;
+    odp_linear_table_imp * linear_tbl;
+    /* Note: for linear table, key must be an uint32_t, its is fixed 4. So, we 
ignore the input key_size here*/
+    (void)key_size;
+
+    if(strlen(name) >= ODP_TABLE_NAME_LEN || capacity < 1 || capacity >= 
0x1000 || value_size == 0)
+    {
+        printf("create para input error or less than !");
+        return NULL;
+    }
+    /* check name confict in shm*/
+    linear_tbl = (odp_linear_table_imp *)odp_shm_addr(odp_shm_lookup(name));
+    if(linear_tbl != NULL)
+    {
+        ODPH_DBG("name already exist\n");
+        return NULL;
+    }
+
+    /* alloc memory from shm */
+    shmem = odp_shm_reserve(name,capacity<<20,64,ODP_SHM_SW_ONLY);
+    if(shmem == ODP_SHM_INVALID)
+    {
+        ODPH_DBG("shm reserve fail\n");
+        return NULL;
+    }
+    linear_tbl = (odp_linear_table_imp *)odp_shm_addr(shmem);
+
+    /* clean this block of memory */
+    memset(linear_tbl,0,capacity<<20);
+    
+    linear_tbl->init_cap = capacity<20;
+
+    strncpy(linear_tbl->name,name,ODP_TABLE_NAME_LEN);
+
+    /* for linear table, the key is just the index, without confict
+     * so we just need to record the value content
+     * there is a rwlock in the head of every node
+     */
+     
+    linear_tbl->value_size = value_size + sizeof(odp_rwlock_t);
+
+    node_num = linear_tbl->init_cap / linear_tbl->value_size;
+    linear_tbl->node_sum = node_num;
+    
+    linear_tbl->data_array = (void*)((char*)linear_tbl + 
sizeof(odp_linear_table_imp));
+
+    /* initialize rwlock*/
+    for(idx = 0;idx < linear_tbl->node_sum;idx++)
+    {
+        odp_rwlock_t* lock = (odp_rwlock_t*)((char*)linear_tbl->data_array + 
idx * linear_tbl->value_size);
+        odp_rwlock_init(lock);
+    }
+
+    linear_tbl->magicword = ODP_LINEAR_TABLE_MAGIC_WORD;
+    
+    return (odp_table_t)(linear_tbl);
+}
+
+int odp_linear_table_destroy(odp_table_t table)
+{
+    int ret;
+    if(table != NULL)
+    {
+        odp_linear_table_imp *linear_tbl = (odp_linear_table_imp*)table;
+        if(linear_tbl->magicword != ODP_LINEAR_TABLE_MAGIC_WORD)
+        {
+            return ODP_FAIL;
+        }
+        ret = odp_shm_free(odp_shm_lookup(linear_tbl->name));
+        if(ret != 0)
+        {
+            ODPH_DBG("free fail\n");
+            return ret;
+        }
+        /* clean head */
+        return ODP_SUCCESS;
+    }
+    return ODP_FAIL;
+}
+
+odp_table_t odp_linear_table_lookup(const char *name)
+{
+    int idx;
+    odp_linear_table_imp * linear_tbl;
+    if(name == NULL || strlen(name) >= ODP_TABLE_NAME_LEN)
+    {
+        return NULL;
+    }
+    linear_tbl = (odp_linear_table_imp *)odp_shm_addr(odp_shm_lookup(name));
+    if(linear_tbl != NULL
+        && linear_tbl->magicword == ODP_LINEAR_TABLE_MAGIC_WORD
+        && strcmp(linear_tbl->name,name) == 0)
+    {
+        return (odp_table_t)linear_tbl;
+    }
+    return NULL;
+}
+
+/* should make sure the input table exists and is available */
+int odp_lineartable_put_value(odp_table_t table, void *key, void *value)
+{
+    odp_linear_table_imp *linear_tbl = (odp_linear_table_imp*)table;
+    uint32_t ikey = 0;
+    void* entry = NULL;
+    odp_rwlock_t* lock = NULL;
+    if(table == NULL || key == NULL || value == NULL)
+    {
+        return ODP_FAIL;
+    }
+
+    ikey = *(uint32_t*)key;
+    if(ikey >= linear_tbl->node_sum)
+    {
+        return ODP_FAIL;
+    }
+    
+    entry = (void *)((char*)linear_tbl->data_array + ikey * 
linear_tbl->value_size);
+    lock = (odp_rwlock_t*)entry;
+    entry = (char*)entry + sizeof(odp_rwlock_t);
+
+    odp_rwlock_write_lock(lock);
+
+    memcpy(entry,value,linear_tbl->value_size - sizeof(odp_rwlock_t));
+
+    odp_rwlock_write_unlock(lock);
+
+    return ODP_SUCCESS;
+}
+
+/* should make sure the input table exists and is available */
+int odp_lineartable_get_value(odp_table_t table, void *key, void *buffer, 
uint32_t buffer_size)
+{
+    odp_linear_table_imp *linear_tbl = (odp_linear_table_imp*)table;
+    uint32_t ikey = 0;
+    void* entry = NULL;
+    odp_rwlock_t* lock = NULL;
+    if(table == NULL || key == NULL || buffer == NULL)
+    {
+        return ODP_FAIL;
+    }
+
+    ikey = *(uint32_t*)key;
+    if(ikey >= linear_tbl->node_sum)
+    {
+        return ODP_FAIL;
+    }
+
+    entry = (void *)((char*)linear_tbl->data_array + ikey * 
linear_tbl->value_size);
+    lock = (odp_rwlock_t*)entry;
+    entry = (char*)entry + sizeof(odp_rwlock_t);
+
+    odp_rwlock_read_lock(lock);
+
+    memcpy(buffer,entry,linear_tbl->value_size - sizeof(odp_rwlock_t));
+
+    odp_rwlock_read_unlock(lock);
+    
+    return ODP_SUCCESS;
+}
+
+struct odp_table_ops odp_linear_table_ops = 
+{
+odp_linear_table_create,
+odp_linear_table_lookup,
+odp_linear_table_destroy,
+odp_lineartable_put_value,
+odp_lineartable_get_value,
+NULL,
+};
+
+
+#ifdef __cplusplus
+}
+#endif
\ No newline at end of file
diff --git a/helper/odp_lineartable.h b/helper/odp_lineartable.h
new file mode 100755
index 0000000..7cfa0da
--- /dev/null
+++ b/helper/odp_lineartable.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 2014, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+
+/**
+ * @file
+ *
+ * ODP Hash table
+ */
+
+#ifndef ODP_HASH_TABLE_H_
+#define ODP_HASH_TABLE_H_
+
+#include <stdint.h>
+#include <odp/plat/strong_types.h>
+#include <odp/helper/odp_table.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    extern odp_table_t odp_linear_table_create(const char *name, uint32_t 
capacity,uint32_t key_size,uint32_t value_size);
+    extern odp_table_t odp_linear_table_lookup(const char *name);
+    extern int   odp_linear_table_destroy(odp_table_t table);
+    extern int   odp_linear_put_value(odp_table_t table, void *key, void 
*value);
+    extern int   odp_linear_get_value(odp_table_t table, void *key, void 
*buffer,uint32_t buffer_size);
+
+    extern struct odp_table_ops odp_linear_table_ops;
+    
+#ifdef __cplusplus
+}
+#endif
+
+#endif
\ No newline at end of file
diff --git a/helper/odp_list_internal.h b/helper/odp_list_internal.h
new file mode 100755
index 0000000..a3743cf
--- /dev/null
+++ b/helper/odp_list_internal.h
@@ -0,0 +1,82 @@
+/* Copyright (c) 2014, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+
+/**
+ * @file
+ *
+ * ODP list
+ */
+
+#ifndef ODP_LIST_INTER_H_
+#define ODP_LIST_INTER_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    typedef struct list_object {
+        struct list_object *next, *prev;
+    } list_object;
+    
+    typedef list_object list_head;
+    
+    static inline void INIT_LIST_HEAD(list_object *list)
+    {
+        list->next = list;
+        list->prev = list;
+
+    }
+    
+    static inline void __list_add(list_object *new,list_object 
*prev,list_object *next)
+    {
+        next->prev = new;
+        new->next = next;
+        new->prev = prev;
+        prev->next = new;
+    }
+    static inline void list_add(list_object *new, struct list_object *head)
+    {
+        __list_add(new, head, head->next);
+    }
+
+    static inline void list_add_tail(struct list_object *new, struct 
list_object *head)
+    {
+        __list_add(new, head->prev, head);
+    }
+    
+    static inline void __list_del(struct list_object * prev, struct 
list_object * next)
+    {
+        next->prev = prev;
+        prev->next = next;
+    }
+    
+    static inline void list_del(struct list_object *entry)
+    {
+        __list_del(entry->prev, entry->next);
+        INIT_LIST_HEAD(entry);
+    }
+    
+    static inline int list_empty(const struct list_object *head)
+    {
+        return head->next == head;
+    }
+       #ifndef offsetof
+    #define offsetof(type, list_node) ((size_t) &((type *)0)->list_node)
+       #endif 
+       
+    #define container_of(ptr, type, list_node) ((type *)(void *)((char *)ptr - 
offsetof(type,list_node)))
+
+    #define LIST_FOR_EACH(pos, list_head, type, list_node) \
+        for (pos = container_of((list_head)->next,type,list_node); \
+             &(pos->list_node) != (list_head); \
+             pos = container_of(pos->list_node.next,type,list_node))
+             
+#ifdef __cplusplus
+}
+#endif
+
+#endif
\ No newline at end of file
diff --git a/helper/test/Makefile.am b/helper/test/Makefile.am
old mode 100644
new mode 100755
index fbf5a9b..06ebe33
--- a/helper/test/Makefile.am
+++ b/helper/test/Makefile.am
@@ -8,7 +8,8 @@ TESTS_ENVIRONMENT += TEST_DIR=${builddir}
 EXECUTABLES = odp_chksum$(EXEEXT) \
               odp_thread$(EXEEXT) \
               odp_process$(EXEEXT)\
-              odph_pause$(EXEEXT)
+              odph_pause$(EXEEXT)\
+              odp_table_test$(EXEEXT)
 
 COMPILE_ONLY =
 
@@ -29,3 +30,5 @@ odp_thread_LDADD = $(LIB)/libodphelper.la $(LIB)/libodp.la
 dist_odp_process_SOURCES = odp_process.c
 odp_process_LDADD = $(LIB)/libodphelper.la $(LIB)/libodp.la
 odph_pause_SOURCES = odph_pause.c
+dist_odp_table_test_SOURCES = odp_table_test.c
+dist_odp_table_test_LDADD = $(LIB)/libodphelper.la $(LIB)/libodp.la
diff --git a/helper/test/odp_table_test.c b/helper/test/odp_table_test.c
new file mode 100755
index 0000000..e9f74b4
--- /dev/null
+++ b/helper/test/odp_table_test.c
@@ -0,0 +1,119 @@
+/* Copyright (c) 2015, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#include <test_debug.h>
+#include <../odp_hashtable.h>
+#include <../odp_lineartable.h>
+#include <odp.h>
+
+extern int odp_shm_init_global(void);
+extern int odp_shm_init_local(void);
+
+int main(int argc TEST_UNUSED, char *argv[] TEST_UNUSED)
+{
+       int ret = 0;
+    odp_table_t table;
+    odp_table_t tmp_tbl;
+    struct odp_table_ops *test_ops;
+    char tmp[32];
+    char ip_addr1[]  = "12345678";
+    char ip_addr2[]  = "11223344";
+    char ip_addr3[]  = "55667788";
+    char mac_addr1[] = "0A1122334401";
+    char mac_addr2[] = "0A1122334402";
+    char mac_addr3[] = "0B4433221101";
+    char mac_addr4[] = "0B4433221102";
+    
+    ret = odp_shm_init_global();
+    if(ret != 0)
+    {
+        printf("odp_shm_init_global fail\n");
+        return 1;
+    }
+    ret = odp_shm_init_local();
+    if(ret != 0)
+    {
+        printf("odp_shm_init_local fail\n");
+        return 1;
+    }
+    
+
+    printf("test hash table:\n");
+    test_ops = &odp_hash_table_ops;
+    
+    table = test_ops->f_create("test",2,4,16);
+    if(table == NULL)
+    {
+        printf("table create fail\n");
+        return 1;
+    }
+    ret += test_ops->f_put(table,&ip_addr1,mac_addr1);
+
+    ret += test_ops->f_put(table,&ip_addr2,mac_addr2);
+
+    ret += test_ops->f_put(table,&ip_addr3,mac_addr3);
+
+    if(ret != 0)
+    {
+        printf("put value fail\n");
+        return 1;
+    }
+
+    ret = test_ops->f_get(table,&ip_addr1,&tmp,32);
+    if(ret != 0)
+    {
+        printf("get value fail\n");
+        return 1;
+    }
+    printf("\t1  get '123' tmp = %s,\n",tmp);
+
+    ret = test_ops->f_put(table,&ip_addr1,mac_addr4);
+    if(ret != 0)
+    {
+        printf("repeat put value fail\n");
+        return 1;
+    }
+
+    ret = test_ops->f_get(table,&ip_addr1,&tmp,32);
+    if(ret != 0 || strcmp(tmp,mac_addr4)!=0)
+    {
+        printf("get value fail\n");
+        return 1;
+    }
+
+    printf("\t2  repeat get '123' value = %s\n",tmp);
+    
+    ret = test_ops->f_remove(table,&ip_addr1);
+    if(ret != 0)
+    {
+        printf("remove value fail\n");
+        return 1;
+    }
+    ret = test_ops->f_get(table,&ip_addr1,tmp,32);
+    if(ret == 0 )
+    {
+        printf("remove value fail actually\n");
+        return 1;
+    }
+    printf("\t3  remove success!\n");
+    
+    tmp_tbl = test_ops->f_lookup("test");
+    if(tmp_tbl != table)
+    {
+        printf("lookup table fail!!!\n");
+    }
+    printf("\t4  lookup table success!\n");
+
+    ret = test_ops->f_des(table);
+    if(ret != 0)
+    {
+        printf("destory table fail!!!\n");
+    }
+    printf("\t5  destory table success!\n");
+  
+    printf("all test finished success!!\n");
+       return 0;
+}
-- 
1.9.1


_______________________________________________
lng-odp mailing list
[email protected]
https://lists.linaro.org/mailman/listinfo/lng-odp

Reply via email to