I see the same behavior.  git am reports the first patch is corrupt at line
14, but patch can apply it.  Not sure what is going on with that.

The test runs fine, however this still has a number of checkpatch issues
that need to be addressed:

WARNING: please, no spaces at the start of a line
#480: FILE: helper/iplookuptable.c:434:
+    return NULL;$

WARNING: braces {} are not necessary for single statement blocks
#532: FILE: helper/iplookuptable.c:486:
+ for (i = 0; i < ENTRY_NUM_L1; i++) {
+ tbl->l1e[i].nexthop = ODP_BUFFER_INVALID;
+ }

WARNING: please, no spaces at the start of a line
#617: FILE: helper/iplookuptable.c:571:
+    return 0;$

WARNING: line over 80 characters
#660: FILE: helper/iplookuptable.c:614:
+ odph_iplookup_table_impl *tbl, prefix_entry_t *entry, odp_buffer_t *buff,

WARNING: line over 80 characters
#730: FILE: helper/iplookuptable.c:684:
+ impl, impl->trie, prefix->ip, prefix->cidr, nexthop);

WARNING: line over 80 characters
#792: FILE: helper/iplookuptable.c:746:
+ odph_iplookup_table_impl *tbl, prefix_entry_t *l1e, odp_buffer_t *buff,

WARNING: line over 80 characters
#872: FILE: helper/iplookuptable.c:826:
+ if (ne->child != 0 || ne->cidr != cidr || ne->nexthop != index) {

WARNING: line over 80 characters
#882: FILE: helper/iplookuptable.c:836:
+ odph_iplookup_table_impl *tbl, prefix_entry_t *e, odp_buffer_t *buff,

WARNING: line over 80 characters
#899: FILE: helper/iplookuptable.c:853:
+ tbl, ne, nbuff, ip, cidr - 8, level + 8, depth + 1);

total: 0 errors, 9 warnings, 0 checks, 1007 lines checked

NOTE: Ignored message types: BIT_MACRO COMPARISON_TO_NULL
DEPRECATED_VARIABLE NEW_TYPEDEFS SPLIT_STRING SSCANF_TO_KSTRTO

0001-helper-table-add-impl-of-ip-lookup-table.patch has style problems,
please review.

If any of these errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.
total: 0 errors, 0 warnings, 0 checks, 187 lines checked

NOTE: Ignored message types: BIT_MACRO COMPARISON_TO_NULL
DEPRECATED_VARIABLE NEW_TYPEDEFS SPLIT_STRING SSCANF_TO_KSTRTO

0002-helper-test-add-validation-test-of-ip-lookup-table.patch has no
obvious style problems and is ready for submission.


On Fri, Jun 17, 2016 at 2:13 AM, Maxim Uvarov <[email protected]>
wrote:

> Bill,
>
> I'm able to apply it with just:
> git am -s -3 /tmp/1/*.eml
> patch -p1 < /opt/Linaro/odp3.git/.git/rebase-apply/patch
> git add -A
> git am --continue
>
> Interesting that git am -3 can not resolve conflicts but patch -p1 works
> fine.
>
> He, Bill is travelling and will be on conference so it will take some time
> for him to respond / review.
>
> Maxim.
>
>
> On 06/17/16 09:01, HePeng wrote:
>
>> Ping?
>>
>>> 在 2016年6月14日,上午9:30,HePeng <[email protected]> 写道:
>>>
>>> Hi, bill
>>> this patch is based on the current API-NEXT …
>>>
>>> 在 2016年6月14日,上午6:24,Bill Fischofer <[email protected]> 写道:
>>>>
>>>> v4 of this patch still doesn't apply for me:
>>>>
>>>> bill@Ubuntu15:~/linaro/review$ git am --reject ~/Mail/Incoming/Ru/5
>>>> Applying: helper: table: add impl of ip lookup table
>>>> fatal: corrupt patch at line 14
>>>> Patch failed at 0001 helper: table: add impl of ip lookup table
>>>> The copy of the patch that failed is found in: .git/rebase-apply/patch
>>>> When you have resolved this problem, run "git am --continue".
>>>> If you prefer to skip this patch, run "git am --skip" instead.
>>>> To restore the original branch and stop patching, run "git am --abort".
>>>>
>>>> Looks like this still needs a rebase on to the current master?
>>>>
>>>> Thanks.
>>>>
>>>> Bill
>>>>
>>>>
>>>>
>>>> On Mon, Jun 13, 2016 at 3:57 AM, Ru Jia <[email protected]> wrote:
>>>>
>>>> This is an implementation of the 16,8,8 ip lookup
>>>>> (longest prefix matching) algorithm. The key of the
>>>>> table is 32-bit IPv4 address.
>>>>>
>>>>> Signed-off-by: Ru Jia <[email protected]>
>>>>> ---
>>>>> helper/Makefile.am          |   4 +-
>>>>> helper/iplookuptable.c      | 934
>>>>> ++++++++++++++++++++++++++++++++++++++++++++
>>>>> helper/odph_iplookuptable.h |  58 +++
>>>>> 3 files changed, 995 insertions(+), 1 deletion(-)
>>>>> create mode 100644 helper/iplookuptable.c
>>>>> create mode 100644 helper/odph_iplookuptable.h
>>>>>
>>>>> diff --git a/helper/Makefile.am b/helper/Makefile.am
>>>>> index aa58e8c..2e1d519 100644
>>>>> --- a/helper/Makefile.am
>>>>> +++ b/helper/Makefile.am
>>>>> @@ -27,6 +27,7 @@ noinst_HEADERS = \
>>>>>                 $(srcdir)/odph_debug.h \
>>>>>                 $(srcdir)/odph_hashtable.h \
>>>>>                 $(srcdir)/odph_lineartable.h \
>>>>> +                $(srcdir)/odph_iplookuptable.h \
>>>>>                 $(srcdir)/odph_list_internal.h
>>>>>
>>>>> __LIB__libodphelper_linux_la_SOURCES = \
>>>>> @@ -35,6 +36,7 @@ __LIB__libodphelper_linux_la_SOURCES = \
>>>>>                                        chksum.c \
>>>>>                                        linux.c \
>>>>>                                        hashtable.c \
>>>>> -                                       lineartable.c
>>>>> +                                       lineartable.c \
>>>>> +                                       iplookuptable.c
>>>>>
>>>>> lib_LTLIBRARIES = $(LIB)/libodphelper-linux.la
>>>>> diff --git a/helper/iplookuptable.c b/helper/iplookuptable.c
>>>>> new file mode 100644
>>>>> index 0000000..8763abc
>>>>> --- /dev/null
>>>>> +++ b/helper/iplookuptable.c
>>>>> @@ -0,0 +1,934 @@
>>>>> +/* Copyright (c) 2016, Linaro Limited
>>>>> + * All rights reserved.
>>>>> + *
>>>>> + * SPDX-License-Identifier:     BSD-3-Clause
>>>>> + */
>>>>> +
>>>>> +#include <string.h>
>>>>> +#include <stdint.h>
>>>>> +#include <errno.h>
>>>>> +#include <stdio.h>
>>>>> +
>>>>> +#include "odph_iplookuptable.h"
>>>>> +#include "odph_list_internal.h"
>>>>> +#include "odph_debug.h"
>>>>> +#include <odp_api.h>
>>>>> +
>>>>> +/** @magic word, write to the first byte of the memory block
>>>>> + *   to indicate this block is used by a ip lookup table
>>>>> + */
>>>>> +#define ODPH_IP_LOOKUP_TABLE_MAGIC_WORD 0xCFCFFCFC
>>>>> +
>>>>> +/* The length(bit) of the IPv4 address */
>>>>> +#define IP_LENGTH 32
>>>>> +
>>>>> +/* The number of L1 entries */
>>>>> +#define ENTRY_NUM_L1           (1 << 16)
>>>>> +/* The size of one L2\L3 subtree */
>>>>> +#define ENTRY_NUM_SUBTREE      (1 << 8)
>>>>> +
>>>>> +#define WHICH_CHILD(ip, cidr) ((ip >> (IP_LENGTH - cidr)) &
>>>>> 0x00000001)
>>>>> +
>>>>> +/** @internal entry struct
>>>>> + *   Structure store an entry of the ip prefix table.
>>>>> + *   Because of the leaf pushing, each entry of the table must have
>>>>> + *   either a child entry, or a nexthop info.
>>>>> + *   If child == 0 and index != ODP_BUFFER_INVALID, this entry has
>>>>> + *             a nexthop info, index indicates the buffer that stores
>>>>> the
>>>>> + *             nexthop value, and ptr points to the address of the
>>>>> buffer.
>>>>> + *   If child == 1, this entry has a subtree, index indicates
>>>>> + *             the buffer that stores the subtree, and ptr points to
>>>>> the
>>>>> + *             address of the buffer.
>>>>> + */
>>>>> +typedef struct {
>>>>> +       union {
>>>>> +               uint8_t u8;
>>>>> +               struct {
>>>>> +#if ODP_BYTE_ORDER == ODP_BIG_ENDIAN
>>>>> +                       uint8_t child : 1;
>>>>> +                       uint8_t cidr  : 7;
>>>>> +#else
>>>>> +                       uint8_t cidr  : 7;
>>>>> +                       uint8_t child : 1;
>>>>> +#endif
>>>>> +               };
>>>>> +       };
>>>>> +       union {
>>>>> +               odp_buffer_t nexthop;
>>>>> +               void *ptr;
>>>>> +       };
>>>>> +} prefix_entry_t;
>>>>> +
>>>>> +#define ENTRY_SIZE (sizeof(prefix_entry_t) + sizeof(odp_buffer_t))
>>>>> +#define ENTRY_BUFF_ARR(x) ((odp_buffer_t *)((char *)x \
>>>>> +                       + sizeof(prefix_entry_t) * ENTRY_NUM_SUBTREE))
>>>>> +
>>>>> +/** @internal trie node struct
>>>>> + *  In this IP lookup algorithm, we use a
>>>>> + *  binary tire to detect the overlap prefix.
>>>>> + */
>>>>> +typedef struct trie_node {
>>>>> +       /* tree structure */
>>>>> +       struct trie_node *parent;
>>>>> +       struct trie_node *left;
>>>>> +       struct trie_node *right;
>>>>> +       /* IP prefix length */
>>>>> +       uint8_t cidr;
>>>>> +       /* Nexthop buffer index */
>>>>> +       odp_buffer_t nexthop;
>>>>> +       /* Buffer that stores this node */
>>>>> +       odp_buffer_t buffer;
>>>>> +} trie_node_t;
>>>>> +
>>>>> +/** Number of L2\L3 entries(subtrees) per cache cube. */
>>>>> +#define CACHE_NUM_SUBTREE      (1 << 13)
>>>>> +/** Number of trie nodes per cache cube. */
>>>>> +#define CACHE_NUM_TRIE         (1 << 20)
>>>>> +
>>>>> +/** @typedef cache_type_t
>>>>> + *     Cache node type
>>>>> + */
>>>>> +typedef enum {
>>>>> +       CACHE_TYPE_SUBTREE = 0,
>>>>> +       CACHE_TYPE_TRIE
>>>>> +} cache_type_t;
>>>>> +
>>>>> +/** A IP lookup table structure. */
>>>>> +typedef struct {
>>>>> +       /**< for check */
>>>>> +       uint32_t magicword;
>>>>> +       /** Name of the hash. */
>>>>> +       char name[ODPH_TABLE_NAME_LEN];
>>>>> +       /** Total L1 entries. */
>>>>> +       prefix_entry_t *l1e;
>>>>> +       /** Root node of the binary trie */
>>>>> +       trie_node_t *trie;
>>>>> +       /** Length of value. */
>>>>> +       uint32_t nexthop_len;
>>>>> +       /** Queues of free slots (caches)
>>>>> +        *  There are three queues:
>>>>> +        *  - free_slots[CACHE_TYPE_SUBTREE] is used for L2 and
>>>>> +        *    L3 entries (subtrees). Each entry stores an 8-bit
>>>>> +        *    subtree.
>>>>> +        *  - free_slots[CACHE_TYPE_TRIE] is used for the binary
>>>>> +        *    trie. Each entry contains a trie node.
>>>>> +        */
>>>>> +       odp_queue_t free_slots[2];
>>>>> +       /** The number of pool used by each queue. */
>>>>> +       uint32_t cache_count[2];
>>>>> +} odph_iplookup_table_impl ODP_ALIGNED_CACHE;
>>>>> +
>>>>> +/***********************************************************
>>>>> + *****************   Cache management   ********************
>>>>> + ***********************************************************/
>>>>> +
>>>>> +/** Destroy all caches */
>>>>> +static void
>>>>> +cache_destroy(odph_iplookup_table_impl *impl)
>>>>> +{
>>>>> +       odp_queue_t queue;
>>>>> +       odp_event_t ev;
>>>>> +       uint32_t i = 0, count = 0;
>>>>> +       char pool_name[ODPH_TABLE_NAME_LEN + 8];
>>>>> +
>>>>> +       /* free all buffers in the queue */
>>>>> +       for (; i < 2; i++) {
>>>>> +               queue = impl->free_slots[i];
>>>>> +               if (queue == ODP_QUEUE_INVALID)
>>>>> +                       continue;
>>>>> +
>>>>> +               while ((ev = odp_queue_deq(queue))
>>>>> +                               != ODP_EVENT_INVALID) {
>>>>> +                       odp_buffer_free(odp_buffer_from_event(ev));
>>>>> +               }
>>>>> +               odp_queue_destroy(queue);
>>>>> +       }
>>>>> +
>>>>> +       /* destroy all cache pools */
>>>>> +       for (i = 0; i < 2; i++) {
>>>>> +               for (count = 0; count < impl->cache_count[i]; count++)
>>>>> {
>>>>> +                       sprintf(
>>>>> +                                       pool_name, "%s_%d_%d",
>>>>> +                                       impl->name, i, count);
>>>>> +                       odp_pool_destroy(odp_pool_lookup(pool_name));
>>>>> +               }
>>>>> +       }
>>>>> +}
>>>>> +
>>>>> +/** According to the type of cahce, set the value of
>>>>> + *  a buffer to the initial value.
>>>>> + */
>>>>> +static void
>>>>> +cache_init_buffer(odp_buffer_t buffer, cache_type_t type, uint32_t
>>>>> size)
>>>>> +{
>>>>> +       int i = 0;
>>>>> +       void *addr = odp_buffer_addr(buffer);
>>>>> +
>>>>> +       memset(addr, 0, size);
>>>>> +       if (type == CACHE_TYPE_SUBTREE) {
>>>>> +               prefix_entry_t *entry = (prefix_entry_t *)addr;
>>>>> +
>>>>> +               for (i = 0; i < ENTRY_NUM_SUBTREE; i++, entry++)
>>>>> +                       entry->nexthop = ODP_BUFFER_INVALID;
>>>>> +       } else if (type == CACHE_TYPE_TRIE) {
>>>>> +               trie_node_t *node = (trie_node_t *)addr;
>>>>> +
>>>>> +               node->buffer = buffer;
>>>>> +               node->nexthop = ODP_BUFFER_INVALID;
>>>>> +       }
>>>>> +}
>>>>> +
>>>>> +/** Create a new buffer pool, and insert its buffer into the queue. */
>>>>> +static int
>>>>> +cache_alloc_new_pool(
>>>>> +               odph_iplookup_table_impl *tbl, cache_type_t type)
>>>>> +{
>>>>> +       odp_pool_t pool;
>>>>> +       odp_pool_param_t param;
>>>>> +       odp_queue_t queue = tbl->free_slots[type];
>>>>> +
>>>>> +       odp_buffer_t buffer;
>>>>> +       char pool_name[ODPH_TABLE_NAME_LEN + 8];
>>>>> +       uint32_t size = 0, num = 0;
>>>>> +
>>>>> +       /* Create new pool (new free buffers). */
>>>>> +       param.type = ODP_POOL_BUFFER;
>>>>> +       param.buf.align = ODP_CACHE_LINE_SIZE;
>>>>> +       if (type == CACHE_TYPE_SUBTREE) {
>>>>> +               num = CACHE_NUM_SUBTREE;
>>>>> +               size = ENTRY_SIZE * ENTRY_NUM_SUBTREE;
>>>>> +       } else if (type == CACHE_TYPE_TRIE) {
>>>>> +               num = CACHE_NUM_TRIE;
>>>>> +               size = sizeof(trie_node_t);
>>>>> +       } else {
>>>>> +               ODPH_DBG("wrong cache_type_t.\n");
>>>>> +               return -1;
>>>>> +       }
>>>>> +       param.buf.size = size;
>>>>> +       param.buf.num = num;
>>>>> +
>>>>> +       sprintf(
>>>>> +                       pool_name, "%s_%d_%d",
>>>>> +                       tbl->name, type, tbl->cache_count[type]);
>>>>> +       pool = odp_pool_create(pool_name, &param);
>>>>> +       if (pool == ODP_POOL_INVALID) {
>>>>> +               ODPH_DBG("failed to create a new pool.\n");
>>>>> +               return -1;
>>>>> +       }
>>>>> +
>>>>> +       /* insert new free buffers into queue */
>>>>> +       while ((buffer = odp_buffer_alloc(pool))
>>>>> +                       != ODP_BUFFER_INVALID) {
>>>>> +               cache_init_buffer(buffer, type, size);
>>>>> +               odp_queue_enq(queue, odp_buffer_to_event(buffer));
>>>>> +       }
>>>>> +
>>>>> +       tbl->cache_count[type]++;
>>>>> +       return 0;
>>>>> +}
>>>>> +
>>>>> +/** Get a new buffer from a cache list. If there is no
>>>>> + *  available buffer, allocate a new pool.
>>>>> + */
>>>>> +static odp_buffer_t
>>>>> +cache_get_buffer(odph_iplookup_table_impl *tbl, cache_type_t type)
>>>>> +{
>>>>> +       odp_buffer_t buffer = ODP_BUFFER_INVALID;
>>>>> +       odp_queue_t queue = tbl->free_slots[type];
>>>>> +
>>>>> +       /* get free buffer from queue */
>>>>> +       buffer = odp_buffer_from_event(
>>>>> +                               odp_queue_deq(queue));
>>>>> +
>>>>> +       /* If there is no free buffer available, allocate new pool */
>>>>> +       if (buffer == ODP_BUFFER_INVALID) {
>>>>> +               cache_alloc_new_pool(tbl, type);
>>>>> +               buffer = odp_buffer_from_event(odp_queue_deq(queue));
>>>>> +       }
>>>>> +
>>>>> +       return buffer;
>>>>> +}
>>>>> +
>>>>> +/***********************************************************
>>>>> + ******************     Binary trie     ********************
>>>>> + ***********************************************************/
>>>>> +
>>>>> +/* Initialize the root node of the trie */
>>>>> +static int
>>>>> +trie_init(odph_iplookup_table_impl *tbl)
>>>>> +{
>>>>> +       trie_node_t *root = NULL;
>>>>> +       odp_buffer_t buffer = cache_get_buffer(tbl, CACHE_TYPE_TRIE);
>>>>> +
>>>>> +       if (buffer != ODP_BUFFER_INVALID) {
>>>>> +               root = (trie_node_t *)odp_buffer_addr(buffer);
>>>>> +               root->cidr = 0;
>>>>> +               tbl->trie = root;
>>>>> +               return 0;
>>>>> +       }
>>>>> +
>>>>> +       return -1;
>>>>> +}
>>>>> +
>>>>> +/* Destroy the whole trie (recursively) */
>>>>> +static void
>>>>> +trie_destroy(odph_iplookup_table_impl *tbl, trie_node_t *trie)
>>>>> +{
>>>>> +       if (trie->left != NULL)
>>>>> +               trie_destroy(tbl, trie->left);
>>>>> +       if (trie->right != NULL)
>>>>> +               trie_destroy(tbl, trie->right);
>>>>> +
>>>>> +       /* destroy this node */
>>>>> +       odp_queue_enq(
>>>>> +                       tbl->free_slots[CACHE_TYPE_TRIE],
>>>>> +                       odp_buffer_to_event(trie->buffer));
>>>>> +}
>>>>> +
>>>>> +/* Insert a new prefix node into the trie
>>>>> + * If the node is already existed, update its nexthop info,
>>>>> + *   Return 0 and set nexthop pointer to INVALID.
>>>>> + * If the node is not exitsed, create this target node and
>>>>> + *   all nodes along the path from root to the target node.
>>>>> + *   Then return 0 and set nexthop pointer points to the
>>>>> + *   new buffer.
>>>>> + * Return -1 for error.
>>>>> + */
>>>>> +static int
>>>>> +trie_insert_node(
>>>>> +               odph_iplookup_table_impl *tbl, trie_node_t *root,
>>>>> +               uint32_t ip, uint8_t cidr, odp_buffer_t nexthop)
>>>>> +{
>>>>> +       uint8_t level = 0, child;
>>>>> +       odp_buffer_t buf;
>>>>> +       trie_node_t *node = root, *prev = root;
>>>>> +
>>>>> +       /* create/update all nodes along the path
>>>>> +        * from root to the new node. */
>>>>> +       for (level = 1; level <= cidr; level++) {
>>>>> +               child = WHICH_CHILD(ip, level);
>>>>> +
>>>>> +               node = child == 0 ? prev->left : prev->right;
>>>>> +               /* If the child node doesn't exit, create it. */
>>>>> +               if (node == NULL) {
>>>>> +                       buf = cache_get_buffer(tbl, CACHE_TYPE_TRIE);
>>>>> +                       if (buf == ODP_BUFFER_INVALID)
>>>>> +                               return -1;
>>>>> +
>>>>> +                       node = (trie_node_t *)odp_buffer_addr(buf);
>>>>> +                       node->cidr = level;
>>>>> +                       node->parent = prev;
>>>>> +
>>>>> +                       if (child == 0)
>>>>> +                               prev->left = node;
>>>>> +                       else
>>>>> +                               prev->right = node;
>>>>> +               }
>>>>> +               prev = node;
>>>>> +       }
>>>>> +
>>>>> +       /* The final one is the target. */
>>>>> +       node->nexthop = nexthop;
>>>>> +       return 0;
>>>>> +}
>>>>> +
>>>>> +/* Delete a node */
>>>>> +static int
>>>>> +trie_delete_node(
>>>>> +               odph_iplookup_table_impl *tbl,
>>>>> +               trie_node_t *root, uint32_t ip, uint8_t cidr)
>>>>> +{
>>>>> +       if (root == NULL)
>>>>> +               return -1;
>>>>> +
>>>>> +       /* The default prefix (root node) cannot be deleted. */
>>>>> +       if (cidr == 0)
>>>>> +               return -1;
>>>>> +
>>>>> +       trie_node_t *node = root, *prev = NULL;
>>>>> +       uint8_t level = 1, child = 0;
>>>>> +       odp_buffer_t tmp;
>>>>> +
>>>>> +       /* Find the target node. */
>>>>> +       for (level = 1; level <= cidr; level++) {
>>>>> +               child = WHICH_CHILD(ip, level);
>>>>> +               node = (child == 0) ? node->left : node->right;
>>>>> +               if (node == NULL) {
>>>>> +                       ODPH_DBG("Trie node is not existed\n");
>>>>> +                       return -1;
>>>>> +               }
>>>>> +       }
>>>>> +
>>>>> +       node->nexthop = ODP_BUFFER_INVALID;
>>>>> +
>>>>> +       /* Delete all redundant nodes along the path. */
>>>>> +       for (level = cidr; level > 0; level--) {
>>>>> +               if (
>>>>> +                       node->left != NULL || node->right != NULL ||
>>>>> +                       node->nexthop != ODP_BUFFER_INVALID)
>>>>> +                       break;
>>>>> +
>>>>> +               child = WHICH_CHILD(ip, level);
>>>>> +               prev = node->parent;
>>>>> +
>>>>> +               /* free trie node */
>>>>> +               tmp = node->buffer;
>>>>> +               cache_init_buffer(
>>>>> +                               tmp, CACHE_TYPE_TRIE,
>>>>> sizeof(trie_node_t));
>>>>> +               odp_queue_enq(
>>>>> +                               tbl->free_slots[CACHE_TYPE_TRIE],
>>>>> +                               odp_buffer_to_event(tmp));
>>>>> +
>>>>> +               if (child == 0)
>>>>> +                       prev->left = NULL;
>>>>> +               else
>>>>> +                       prev->right = NULL;
>>>>> +               node = prev;
>>>>> +       }
>>>>> +       return 0;
>>>>> +}
>>>>> +
>>>>> +/* Detect the longest overlapping prefix. */
>>>>> +static int
>>>>> +trie_detect_overlap(
>>>>> +               trie_node_t *trie, uint32_t ip, uint8_t cidr,
>>>>> +               uint8_t leaf_push, uint8_t *over_cidr,
>>>>> +               odp_buffer_t *over_nexthop)
>>>>> +{
>>>>> +       uint8_t child = 0;
>>>>> +       uint32_t level, limit = cidr > leaf_push ? leaf_push + 1 :
>>>>> cidr;
>>>>> +       trie_node_t *node = trie, *longest = trie;
>>>>> +
>>>>> +       for (level = 1; level < limit; level++) {
>>>>> +               child = WHICH_CHILD(ip, level);
>>>>> +               node = (child == 0) ? node->left : node->right;
>>>>> +               if (node->nexthop != ODP_BUFFER_INVALID)
>>>>> +                       longest = node;
>>>>> +       }
>>>>> +
>>>>> +       *over_cidr = longest->cidr;
>>>>> +       *over_nexthop = longest->nexthop;
>>>>> +       return 0;
>>>>> +}
>>>>> +
>>>>> +/***********************************************************
>>>>> + ***************   IP prefix lookup table   ****************
>>>>> + ***********************************************************/
>>>>> +
>>>>> +odph_table_t
>>>>> +odph_iplookup_table_lookup(const char *name)
>>>>> +{
>>>>> +       odph_iplookup_table_impl *tbl = NULL;
>>>>> +
>>>>> +       if (name == NULL || strlen(name) >= ODPH_TABLE_NAME_LEN)
>>>>> +               return NULL;
>>>>> +
>>>>> +       tbl = (odph_iplookup_table_impl
>>>>> *)odp_shm_addr(odp_shm_lookup(name));
>>>>> +
>>>>> +       if (
>>>>> +               tbl != NULL &&
>>>>> +               tbl->magicword == ODPH_IP_LOOKUP_TABLE_MAGIC_WORD &&
>>>>> +               strcmp(tbl->name, name) == 0)
>>>>> +               return (odph_table_t)tbl;
>>>>> +
>>>>> +    return NULL;
>>>>> +}
>>>>> +
>>>>> +odph_table_t
>>>>> +odph_iplookup_table_create(
>>>>> +               const char *name, uint32_t ODP_IGNORED_1,
>>>>> +               uint32_t ODP_IGNORED_2, uint32_t value_size)
>>>>> +{
>>>>> +       odph_iplookup_table_impl *tbl;
>>>>> +       odp_shm_t shm_tbl;
>>>>> +       odp_queue_t queue;
>>>>> +       odp_queue_param_t qparam;
>>>>> +
>>>>> +       unsigned i;
>>>>> +       uint32_t impl_size, l1_size;
>>>>> +       char queue_name[ODPH_TABLE_NAME_LEN + 2];
>>>>> +
>>>>> +       /* Check for valid parameters */
>>>>> +       if (strlen(name) == 0) {
>>>>> +               ODPH_DBG("invalid parameters\n");
>>>>> +               return NULL;
>>>>> +       }
>>>>> +
>>>>> +       /* Guarantee there's no existing */
>>>>> +       tbl = (odph_iplookup_table_impl
>>>>> *)odph_iplookup_table_lookup(name);
>>>>> +       if (tbl != NULL) {
>>>>> +               ODPH_DBG("IP prefix table %s already exists\n", name);
>>>>> +               return NULL;
>>>>> +       }
>>>>> +
>>>>> +       /* Calculate the sizes of different parts of IP prefix table */
>>>>> +       impl_size = sizeof(odph_iplookup_table_impl);
>>>>> +       l1_size = ENTRY_SIZE * ENTRY_NUM_L1;
>>>>> +
>>>>> +       shm_tbl = odp_shm_reserve(
>>>>> +                               name, impl_size + l1_size,
>>>>> +                               ODP_CACHE_LINE_SIZE, ODP_SHM_SW_ONLY);
>>>>> +
>>>>> +       if (shm_tbl == ODP_SHM_INVALID) {
>>>>> +               ODPH_DBG(
>>>>> +                       "shm allocation failed for
>>>>> odph_iplookup_table_impl %s\n",
>>>>> +                       name);
>>>>> +               return NULL;
>>>>> +       }
>>>>> +
>>>>> +       tbl = (odph_iplookup_table_impl *)odp_shm_addr(shm_tbl);
>>>>> +       memset(tbl, 0, impl_size + l1_size);
>>>>> +
>>>>> +       /* header of this mem block is the table impl struct,
>>>>> +        * then the l1 entries array.
>>>>> +        */
>>>>> +       tbl->l1e = (prefix_entry_t *)((char *)tbl + impl_size);
>>>>> +       for (i = 0; i < ENTRY_NUM_L1; i++) {
>>>>> +               tbl->l1e[i].nexthop = ODP_BUFFER_INVALID;
>>>>> +       }
>>>>> +
>>>>> +       /* Setup table context. */
>>>>> +       snprintf(tbl->name, sizeof(tbl->name), "%s", name);
>>>>> +       tbl->magicword = ODPH_IP_LOOKUP_TABLE_MAGIC_WORD;
>>>>> +       tbl->nexthop_len = value_size;
>>>>> +
>>>>> +       /* Initialize cache */
>>>>> +       for (i = 0; i < 2; i++) {
>>>>> +               tbl->cache_count[i] = 0;
>>>>> +
>>>>> +               odp_queue_param_init(&qparam);
>>>>> +               qparam.type = ODP_QUEUE_TYPE_PLAIN;
>>>>> +               sprintf(queue_name, "%s_%d", name, i);
>>>>> +               queue = odp_queue_create(queue_name, &qparam);
>>>>> +               if (queue == ODP_QUEUE_INVALID) {
>>>>> +                       ODPH_DBG("failed to create queue");
>>>>> +                       cache_destroy(tbl);
>>>>> +                       return NULL;
>>>>> +               }
>>>>> +               tbl->free_slots[i] = queue;
>>>>> +               cache_alloc_new_pool(tbl, i);
>>>>> +       }
>>>>> +
>>>>> +       /* Initialize tire */
>>>>> +       if (trie_init(tbl) < 0) {
>>>>> +               odp_shm_free(shm_tbl);
>>>>> +               return NULL;
>>>>> +       }
>>>>> +
>>>>> +       return (odph_table_t)tbl;
>>>>> +}
>>>>> +
>>>>> +int
>>>>> +odph_iplookup_table_destroy(odph_table_t tbl)
>>>>> +{
>>>>> +       int i, j;
>>>>> +       odph_iplookup_table_impl *impl = NULL;
>>>>> +       prefix_entry_t *subtree = NULL;
>>>>> +       odp_buffer_t *buff1 = NULL, *buff2 = NULL;
>>>>> +
>>>>> +       if (tbl == NULL)
>>>>> +               return -1;
>>>>> +
>>>>> +       impl = (odph_iplookup_table_impl *)tbl;
>>>>> +
>>>>> +       /* check magic word */
>>>>> +       if (impl->magicword != ODPH_IP_LOOKUP_TABLE_MAGIC_WORD) {
>>>>> +               ODPH_DBG("wrong magicword for IP prefix table\n");
>>>>> +               return -1;
>>>>> +       }
>>>>> +
>>>>> +       /* destroy trie */
>>>>> +       trie_destroy(impl, impl->trie);
>>>>> +
>>>>> +       /* free all L2 and L3 entries */
>>>>> +       buff1 = ENTRY_BUFF_ARR(impl->l1e);
>>>>> +       for (i = 0; i < ENTRY_NUM_L1; i++) {
>>>>> +               if ((impl->l1e[i]).child == 0)
>>>>> +                       continue;
>>>>> +
>>>>> +               subtree = (prefix_entry_t *)impl->l1e[i].ptr;
>>>>> +               buff2 = ENTRY_BUFF_ARR(subtree);
>>>>> +               /* destroy all l3 subtrees of this l2 subtree */
>>>>> +               for (j = 0; j < ENTRY_NUM_SUBTREE; j++) {
>>>>> +                       if (subtree[j].child == 0)
>>>>> +                               continue;
>>>>> +                       odp_queue_enq(
>>>>> +
>>>>>  impl->free_slots[CACHE_TYPE_TRIE],
>>>>> +                                       odp_buffer_to_event(buff2[j]));
>>>>> +               }
>>>>> +               /* destroy this l2 subtree */
>>>>> +               odp_queue_enq(
>>>>> +                               impl->free_slots[CACHE_TYPE_TRIE],
>>>>> +                               odp_buffer_to_event(buff1[i]));
>>>>> +       }
>>>>> +
>>>>> +       /* destroy all cache */
>>>>> +       cache_destroy(impl);
>>>>> +
>>>>> +       /* free impl */
>>>>> +       odp_shm_free(odp_shm_lookup(impl->name));
>>>>> +
>>>>> +    return 0;
>>>>> +}
>>>>> +
>>>>> +/* Insert the prefix into level x
>>>>> + * Return:
>>>>> + *   -1        error
>>>>> + *   0 the table is unmodified
>>>>> + *   1 the table is modified
>>>>> + */
>>>>> +static int
>>>>> +prefix_insert_into_lx(
>>>>> +               odph_iplookup_table_impl *tbl, prefix_entry_t *entry,
>>>>> +               uint8_t cidr, odp_buffer_t nexthop, uint8_t level)
>>>>> +{
>>>>> +       uint8_t ret = 0;
>>>>> +       uint32_t i = 0, limit = (1 << (level - cidr));
>>>>> +       prefix_entry_t *e = entry, *ne = NULL;
>>>>> +
>>>>> +       for (i = 0; i < limit; i++, e++) {
>>>>> +               if (e->child == 1) {
>>>>> +                       if (e->cidr > cidr)
>>>>> +                               continue;
>>>>> +
>>>>> +                       e->cidr = cidr;
>>>>> +                       /* push to next level */
>>>>> +                       ne = (prefix_entry_t *)e->ptr;
>>>>> +                       ret = prefix_insert_into_lx(
>>>>> +                                       tbl, ne, cidr, nexthop, cidr +
>>>>> 8);
>>>>> +               } else {
>>>>> +                       if (e->cidr > cidr)
>>>>> +                               continue;
>>>>> +
>>>>> +                       e->child = 0;
>>>>> +                       e->cidr = cidr;
>>>>> +                       e->nexthop = nexthop;
>>>>> +                       ret = 1;
>>>>> +               }
>>>>> +       }
>>>>> +       return ret;
>>>>> +}
>>>>> +
>>>>> +static int
>>>>> +prefix_insert_iter(
>>>>> +               odph_iplookup_table_impl *tbl, prefix_entry_t *entry,
>>>>> odp_buffer_t *buff,
>>>>> +               uint32_t ip, uint8_t cidr, odp_buffer_t nexthop,
>>>>> +               uint8_t level, uint8_t depth)
>>>>> +{
>>>>> +       uint8_t state = 0;
>>>>> +       prefix_entry_t *ne = NULL;
>>>>> +       odp_buffer_t *nbuff = NULL;
>>>>> +
>>>>> +       /* If child subtree is existed, get it. */
>>>>> +       if (entry->child) {
>>>>> +               ne = (prefix_entry_t *)entry->ptr;
>>>>> +               nbuff = ENTRY_BUFF_ARR(ne);
>>>>> +       } else {
>>>>> +               /* If the child is not existed, create a new subtree.
>>>>> */
>>>>> +               odp_buffer_t buf, push = entry->nexthop;
>>>>> +
>>>>> +               buf = cache_get_buffer(tbl, CACHE_TYPE_SUBTREE);
>>>>> +               if (buf == ODP_BUFFER_INVALID) {
>>>>> +                       ODPH_DBG("failed to get subtree buffer from
>>>>> cache.\n");
>>>>> +                       return -1;
>>>>> +               }
>>>>> +               ne = (prefix_entry_t *)odp_buffer_addr(buf);
>>>>> +               nbuff = ENTRY_BUFF_ARR(ne);
>>>>> +
>>>>> +               entry->child = 1;
>>>>> +               entry->ptr = ne;
>>>>> +               *buff = buf;
>>>>> +
>>>>> +               /* If this entry contains a nexthop and a small cidr,
>>>>> +                * push it to the next level.
>>>>> +                */
>>>>> +               if (entry->cidr > 0) {
>>>>> +                       state = prefix_insert_into_lx(
>>>>> +                                       tbl, ne, entry->cidr,
>>>>> +                                       push, entry->cidr + 8);
>>>>> +               }
>>>>> +       }
>>>>> +
>>>>> +       ne += (ip >> 24);
>>>>> +       nbuff += (ip >> 24);
>>>>> +       if (cidr <= 8) {
>>>>> +               state = prefix_insert_into_lx(
>>>>> +                               tbl, ne, cidr + depth * 8, nexthop,
>>>>> level);
>>>>> +       } else {
>>>>> +               state = prefix_insert_iter(
>>>>> +                               tbl, ne, nbuff, ip << 8, cidr - 8,
>>>>> +                               nexthop, level + 8, depth + 1);
>>>>> +       }
>>>>> +
>>>>> +       return state;
>>>>> +}
>>>>> +
>>>>> +int
>>>>> +odph_iplookup_table_put_value(odph_table_t tbl, void *key, void
>>>>> *value)
>>>>> +{
>>>>> +       if ((tbl == NULL) || (key == NULL) || (value == NULL))
>>>>> +               return -1;
>>>>> +
>>>>> +       odph_iplookup_table_impl *impl = (odph_iplookup_table_impl
>>>>> *)tbl;
>>>>> +       odph_iplookup_prefix_t *prefix = (odph_iplookup_prefix_t *)key;
>>>>> +       prefix_entry_t *l1e = NULL;
>>>>> +       odp_buffer_t nexthop = *((odp_buffer_t *)value);
>>>>> +       int ret = 0;
>>>>> +
>>>>> +       if (prefix->cidr == 0)
>>>>> +               return -1;
>>>>> +       prefix->ip = prefix->ip & (0xffffffff << (IP_LENGTH -
>>>>> prefix->cidr));
>>>>> +
>>>>> +       /* insert into trie */
>>>>> +       ret = trie_insert_node(
>>>>> +                               impl, impl->trie, prefix->ip,
>>>>> prefix->cidr, nexthop);
>>>>> +
>>>>> +       if (ret < 0) {
>>>>> +               ODPH_DBG("failed to insert into trie\n");
>>>>> +               return -1;
>>>>> +       }
>>>>> +
>>>>> +       /* get L1 entry */
>>>>> +       l1e = &impl->l1e[prefix->ip >> 16];
>>>>> +       odp_buffer_t *buff = ENTRY_BUFF_ARR(impl->l1e) + (prefix->ip >>
>>>>> 16);
>>>>> +
>>>>> +       if (prefix->cidr <= 16) {
>>>>> +               ret = prefix_insert_into_lx(
>>>>> +                               impl, l1e, prefix->cidr, nexthop, 16);
>>>>> +       } else {
>>>>> +               ret = prefix_insert_iter(
>>>>> +                               impl, l1e, buff,
>>>>> +                               ((prefix->ip) << 16), prefix->cidr -
>>>>> 16,
>>>>> +                               nexthop, 24, 2);
>>>>> +       }
>>>>> +
>>>>> +       return ret;
>>>>> +}
>>>>> +
>>>>> +int
>>>>> +odph_iplookup_table_get_value(
>>>>> +               odph_table_t tbl, void *key, void *buffer, uint32_t
>>>>> buffer_size)
>>>>> +{
>>>>> +       if ((tbl == NULL) || (key == NULL) || (buffer == NULL))
>>>>> +               return -EINVAL;
>>>>> +
>>>>> +       odph_iplookup_table_impl *impl = (odph_iplookup_table_impl
>>>>> *)tbl;
>>>>> +       uint32_t ip = *((uint32_t *)key);
>>>>> +       prefix_entry_t *entry = &impl->l1e[ip >> 16];
>>>>> +       odp_buffer_t *buff = (odp_buffer_t *)buffer;
>>>>> +
>>>>> +       if (entry == NULL) {
>>>>> +               ODPH_DBG("failed to get L1 entry.\n");
>>>>> +               return -1;
>>>>> +       }
>>>>> +
>>>>> +       ip <<= 16;
>>>>> +       while (entry->child) {
>>>>> +               entry = (prefix_entry_t *)entry->ptr;
>>>>> +               entry += ip >> 24;
>>>>> +               ip <<= 8;
>>>>> +       }
>>>>> +
>>>>> +       /* copy data */
>>>>> +       if (entry->nexthop == ODP_BUFFER_INVALID) {
>>>>> +               /* ONLY match the default prefix */
>>>>> +               printf("only match the default prefix\n");
>>>>> +               *buff = ODP_BUFFER_INVALID;
>>>>> +       } else {
>>>>> +               *buff = entry->nexthop;
>>>>> +       }
>>>>> +
>>>>> +       return 0;
>>>>> +}
>>>>> +
>>>>> +static int
>>>>> +prefix_delete_lx(
>>>>> +               odph_iplookup_table_impl *tbl, prefix_entry_t *l1e,
>>>>> odp_buffer_t *buff,
>>>>> +               uint8_t cidr, uint8_t over_cidr, odp_buffer_t
>>>>> over_nexthop,
>>>>> +               uint8_t level)
>>>>> +{
>>>>> +       uint8_t ret, flag = 1;
>>>>> +       prefix_entry_t *e = l1e;
>>>>> +       odp_buffer_t *b = buff;
>>>>> +       uint32_t i = 0, limit = 1 << (level - cidr);
>>>>> +
>>>>> +       for (i = 0; i < limit; i++, e++, b++) {
>>>>> +               if (e->child == 1) {
>>>>> +                       if (e->cidr > cidr) {
>>>>> +                               flag = 0;
>>>>> +                               continue;
>>>>> +                       }
>>>>> +
>>>>> +                       prefix_entry_t *ne = (prefix_entry_t *)e->ptr;
>>>>> +                       odp_buffer_t *nbuff = ENTRY_BUFF_ARR(ne);
>>>>> +
>>>>> +                       e->cidr = over_cidr;
>>>>> +                       ret = prefix_delete_lx(
>>>>> +                                       tbl, ne, nbuff, cidr,
>>>>> over_cidr,
>>>>> +                                       over_nexthop, cidr + 8);
>>>>> +
>>>>> +                       /* If ret == 1, the next 2^8 entries equal to
>>>>> +                        * (over_cidr, over_nexthop). In this case, we
>>>>> +                        * should not push the (over_cidr,
>>>>> over_nexthop)
>>>>> +                        * to the next level. In fact, we should
>>>>> recycle
>>>>> +                        * the next 2^8 entries.
>>>>> +                        */
>>>>> +                       if (ret) {
>>>>> +                               /* destroy subtree */
>>>>> +                               cache_init_buffer(
>>>>> +                                       *b, CACHE_TYPE_SUBTREE,
>>>>> +                                       ENTRY_SIZE *
>>>>> ENTRY_NUM_SUBTREE);
>>>>> +                               odp_queue_enq(
>>>>> +
>>>>> tbl->free_slots[CACHE_TYPE_SUBTREE],
>>>>> +                                       odp_buffer_to_event(*b));
>>>>> +                               e->child = 0;
>>>>> +                               e->nexthop = over_nexthop;
>>>>> +                       } else {
>>>>> +                               flag = 0;
>>>>> +                       }
>>>>> +               } else {
>>>>> +                       if (e->cidr > cidr) {
>>>>> +                               flag = 0;
>>>>> +                               continue;
>>>>> +                       } else {
>>>>> +                               e->cidr = over_cidr;
>>>>> +                               e->nexthop = over_nexthop;
>>>>> +                       }
>>>>> +               }
>>>>> +       }
>>>>> +       return flag;
>>>>> +}
>>>>> +
>>>>> +/* Check if the entry can be recycled.
>>>>> + * An entry can be recycled duo to two reasons:
>>>>> + * - all children of the entry are the same,
>>>>> + * - all children of the entry have a cidr smaller than the level
>>>>> + *   bottom bound.
>>>>> + */
>>>>> +static uint8_t
>>>>> +can_recycle(prefix_entry_t *e, uint32_t level)
>>>>> +{
>>>>> +       uint8_t recycle = 1;
>>>>> +       int i = 1;
>>>>> +       prefix_entry_t *ne = (prefix_entry_t *)e->ptr;
>>>>> +
>>>>> +       if (ne->child)
>>>>> +               return 0;
>>>>> +
>>>>> +       uint8_t cidr = ne->cidr;
>>>>> +       odp_buffer_t index = ne->nexthop;
>>>>> +
>>>>> +       if (cidr > level)
>>>>> +               return 0;
>>>>> +
>>>>> +       ne++;
>>>>> +       for (; i < 256; i++, ne++) {
>>>>> +               if (ne->child != 0 || ne->cidr != cidr || ne->nexthop
>>>>> !=
>>>>> index) {
>>>>> +                       recycle = 0;
>>>>> +                       break;
>>>>> +               }
>>>>> +       }
>>>>> +       return recycle;
>>>>> +}
>>>>> +
>>>>> +static uint8_t
>>>>> +prefix_delete_iter(
>>>>> +               odph_iplookup_table_impl *tbl, prefix_entry_t *e,
>>>>> odp_buffer_t *buff,
>>>>> +               uint32_t ip, uint8_t cidr, uint8_t level, uint8_t
>>>>> depth)
>>>>> +{
>>>>> +       uint8_t ret = 0, over_cidr;
>>>>> +       odp_buffer_t over_nexthop;
>>>>> +
>>>>> +       trie_detect_overlap(
>>>>> +                       tbl->trie, ip, cidr + 8 * depth, level,
>>>>> +                       &over_cidr, &over_nexthop);
>>>>> +       if (cidr > 8) {
>>>>> +               prefix_entry_t *ne =
>>>>> +                       (prefix_entry_t *)e->ptr;
>>>>> +               odp_buffer_t *nbuff = ENTRY_BUFF_ARR(ne);
>>>>> +
>>>>> +               ne += ((uint32_t)(ip << level) >> 24);
>>>>> +               nbuff += ((uint32_t)(ip << level) >> 24);
>>>>> +               ret = prefix_delete_iter(
>>>>> +                               tbl, ne, nbuff, ip, cidr - 8, level +
>>>>> 8,
>>>>> depth + 1);
>>>>> +
>>>>> +               if (ret && can_recycle(e, level)) {
>>>>> +                       /* destroy subtree */
>>>>> +                       cache_init_buffer(
>>>>> +                               *buff, CACHE_TYPE_SUBTREE,
>>>>> +                               ENTRY_SIZE * ENTRY_NUM_SUBTREE);
>>>>> +                       odp_queue_enq(
>>>>> +                               tbl->free_slots[CACHE_TYPE_SUBTREE],
>>>>> +                               odp_buffer_to_event(*buff));
>>>>> +                       e->child = 0;
>>>>> +                       e->nexthop = over_nexthop;
>>>>> +                       e->cidr = over_cidr;
>>>>> +                       return 1;
>>>>> +               }
>>>>> +               return 0;
>>>>> +       }
>>>>> +
>>>>> +       ret = prefix_delete_lx(
>>>>> +                       tbl, e, buff, cidr + 8 * depth,
>>>>> +                       over_cidr, over_nexthop, level);
>>>>> +       return ret;
>>>>> +}
>>>>> +
>>>>> +int
>>>>> +odph_iplookup_table_remove_value(odph_table_t tbl, void *key)
>>>>> +{
>>>>> +       if ((tbl == NULL) || (key == NULL))
>>>>> +               return -EINVAL;
>>>>> +
>>>>> +       odph_iplookup_table_impl *impl = (odph_iplookup_table_impl
>>>>> *)tbl;
>>>>> +       odph_iplookup_prefix_t *prefix = (odph_iplookup_prefix_t *)key;
>>>>> +       uint32_t ip = prefix->ip;
>>>>> +       uint8_t cidr = prefix->cidr;
>>>>> +
>>>>> +       if (prefix->cidr < 0)
>>>>> +               return -EINVAL;
>>>>> +
>>>>> +       prefix_entry_t *entry = &impl->l1e[ip >> 16];
>>>>> +       odp_buffer_t *buff = ENTRY_BUFF_ARR(impl->l1e) + (ip >> 16);
>>>>> +       uint8_t over_cidr, ret;
>>>>> +       odp_buffer_t over_nexthop;
>>>>> +
>>>>> +       trie_detect_overlap(
>>>>> +                       impl->trie, ip, cidr, 16, &over_cidr,
>>>>> &over_nexthop);
>>>>> +
>>>>> +       if (cidr <= 16) {
>>>>> +               prefix_delete_lx(
>>>>> +                       impl, entry, buff, cidr, over_cidr,
>>>>> over_nexthop,
>>>>> 16);
>>>>> +       } else {
>>>>> +               prefix_entry_t *ne = (prefix_entry_t *)entry->ptr;
>>>>> +               odp_buffer_t *nbuff = ENTRY_BUFF_ARR(ne);
>>>>> +
>>>>> +               ne += ((uint32_t)(ip << 16) >> 24);
>>>>> +               nbuff += ((uint32_t)(ip << 16) >> 24);
>>>>> +               ret = prefix_delete_iter(impl, ne, nbuff, ip, cidr -
>>>>> 16,
>>>>> 24, 2);
>>>>> +
>>>>> +               if (ret && can_recycle(entry, 16)) {
>>>>> +                       /* destroy subtree */
>>>>> +                       cache_init_buffer(
>>>>> +                               *buff, CACHE_TYPE_SUBTREE,
>>>>> +                               sizeof(prefix_entry_t) *
>>>>> ENTRY_NUM_SUBTREE);
>>>>> +                       odp_queue_enq(
>>>>> +                               impl->free_slots[CACHE_TYPE_SUBTREE],
>>>>> +                               odp_buffer_to_event(*buff));
>>>>> +                       entry->child = 0;
>>>>> +                       entry->cidr = over_cidr;
>>>>> +                       entry->nexthop = over_nexthop;
>>>>> +               }
>>>>> +       }
>>>>> +
>>>>> +       return trie_delete_node(impl, impl->trie, ip, cidr);
>>>>> +}
>>>>> +
>>>>> +odph_table_ops_t odph_iplookup_table_ops = {
>>>>> +       odph_iplookup_table_create,
>>>>> +       odph_iplookup_table_lookup,
>>>>> +       odph_iplookup_table_destroy,
>>>>> +       odph_iplookup_table_put_value,
>>>>> +       odph_iplookup_table_get_value,
>>>>> +       odph_iplookup_table_remove_value
>>>>> +};
>>>>> diff --git a/helper/odph_iplookuptable.h b/helper/odph_iplookuptable.h
>>>>> new file mode 100644
>>>>> index 0000000..e6040ca
>>>>> --- /dev/null
>>>>> +++ b/helper/odph_iplookuptable.h
>>>>> @@ -0,0 +1,58 @@
>>>>> +/* Copyright (c) 2016, Linaro Limited
>>>>> + * All rights reserved.
>>>>> + *
>>>>> + * SPDX-License-Identifier:    BSD-3-Clause
>>>>> + */
>>>>> +
>>>>> +/**
>>>>> + * @file
>>>>> + *
>>>>> + * ODP IP Lookup Table
>>>>> + *
>>>>> + * This is an implementation of the IP lookup table. The key of
>>>>> + * this table is IPv4 address (32 bits), and the value can be
>>>>> + * defined by user. This table uses the 16,8,8 ip lookup (longest
>>>>> + * prefix matching) algorithm.
>>>>> + */
>>>>> +
>>>>> +#ifndef odph_iplookup_TABLE_H_
>>>>> +#define odph_iplookup_TABLE_H_
>>>>> +
>>>>> +#include <odp/helper/table.h>
>>>>> +
>>>>> +#ifdef __cplusplus
>>>>> +extern "C" {
>>>>> +#endif
>>>>> +
>>>>> +typedef struct {
>>>>> +       uint32_t ip;
>>>>> +       uint8_t cidr;
>>>>> +} odph_iplookup_prefix_t;
>>>>> +
>>>>> +odph_table_t odph_iplookup_table_create(
>>>>> +               const char *name,
>>>>> +               uint32_t ODP_IGNORED_1,
>>>>> +               uint32_t ODP_IGNORED_2,
>>>>> +               uint32_t value_size);
>>>>> +
>>>>> +odph_table_t odph_iplookup_table_lookup(const char *name);
>>>>> +
>>>>> +int odph_iplookup_table_destroy(odph_table_t table);
>>>>> +
>>>>> +int odph_iplookup_table_put_value(
>>>>> +               odph_table_t table, void *key, void *value);
>>>>> +
>>>>> +int odph_iplookup_table_get_value(
>>>>> +               odph_table_t table, void *key,
>>>>> +               void *buffer, uint32_t buffer_size);
>>>>> +
>>>>> +int odph_iplookup_table_remove_value(
>>>>> +               odph_table_t table, void *key);
>>>>> +
>>>>> +extern odph_table_ops_t odph_iplookup_table_ops;
>>>>> +
>>>>> +#ifdef __cplusplus
>>>>> +}
>>>>> +#endif
>>>>> +
>>>>> +#endif /* odph_iplookup_TABLE_H_ */
>>>>> --
>>>>> 1.9.1
>>>>>
>>>>> _______________________________________________
>>>>> lng-odp mailing list
>>>>> [email protected]
>>>>> https://lists.linaro.org/mailman/listinfo/lng-odp
>>>>>
>>>>> _______________________________________________
>>>> lng-odp mailing list
>>>> [email protected]
>>>> https://lists.linaro.org/mailman/listinfo/lng-odp
>>>>
>>>
>> _______________________________________________
>> lng-odp mailing list
>> [email protected]
>> https://lists.linaro.org/mailman/listinfo/lng-odp
>>
>
> _______________________________________________
> lng-odp mailing list
> [email protected]
> https://lists.linaro.org/mailman/listinfo/lng-odp
>
_______________________________________________
lng-odp mailing list
[email protected]
https://lists.linaro.org/mailman/listinfo/lng-odp

Reply via email to