get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/35333/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 35333,
    "url": "http://patches.dpdk.org/api/patches/35333/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1519249495-16594-2-git-send-email-medvedkinv@gmail.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1519249495-16594-2-git-send-email-medvedkinv@gmail.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1519249495-16594-2-git-send-email-medvedkinv@gmail.com",
    "date": "2018-02-21T21:44:54",
    "name": "[dpdk-dev,v2,1/2] Add RIB library",
    "commit_ref": null,
    "pull_url": null,
    "state": "rejected",
    "archived": true,
    "hash": "b6dcc581de0887f11b71abdb7ba82c88dabc4c77",
    "submitter": {
        "id": 210,
        "url": "http://patches.dpdk.org/api/people/210/?format=api",
        "name": "Vladimir Medvedkin",
        "email": "medvedkinv@gmail.com"
    },
    "delegate": null,
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1519249495-16594-2-git-send-email-medvedkinv@gmail.com/mbox/",
    "series": [],
    "comments": "http://patches.dpdk.org/api/patches/35333/comments/",
    "check": "fail",
    "checks": "http://patches.dpdk.org/api/patches/35333/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 8C138A84F;\n\tWed, 21 Feb 2018 22:09:13 +0100 (CET)",
            "from mailrelay1.rambler.ru (mailrelay1.rambler.ru [81.19.66.239])\n\tby dpdk.org (Postfix) with ESMTP id 619642C57\n\tfor <dev@dpdk.org>; Wed, 21 Feb 2018 22:09:09 +0100 (CET)",
            "from test02.park.rambler.ru (dpdk01.infra.rambler.ru\n\t[10.16.253.100])\n\tby mailrelay1.rambler.ru (Postfix) with ESMTP id 3zmqq863hSzLm6;\n\tThu, 22 Feb 2018 00:09:08 +0300 (MSK)"
        ],
        "From": "Medvedkin Vladimir <medvedkinv@gmail.com>",
        "To": "dev@dpdk.org",
        "Cc": "Medvedkin Vladimir <medvedkinv@gmail.com>",
        "Date": "Wed, 21 Feb 2018 21:44:54 +0000",
        "Message-Id": "<1519249495-16594-2-git-send-email-medvedkinv@gmail.com>",
        "X-Mailer": "git-send-email 1.9.1",
        "In-Reply-To": "<1519249495-16594-1-git-send-email-medvedkinv@gmail.com>",
        "References": "<1519249495-16594-1-git-send-email-medvedkinv@gmail.com>",
        "X-Rcpt-To": "<medvedkinv@gmail.com>, <dev@dpdk.org>",
        "Subject": "[dpdk-dev] [PATCH v2 1/2] Add RIB library",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "RIB is an alternative to current LPM library.\nIt solves the following problems\n - Increases the speed of control plane operations against lpm such as\n   adding/deleting routes\n - Adds abstraction from dataplane algorithms, so it is possible to add\n   different ip route lookup algorythms such as DXR/poptrie/lpc-trie/etc\n   in addition to current dir24_8\n - It is possible to keep user defined application specific additional\n   information in struct rte_rib_node which represents route entry.\n   It can be next hop/set of next hops (i.e. active and feasible),\n   pointers to link rte_rib_node based on some criteria (i.e. next_hop),\n   plenty of additional control plane information.\n - For dir24_8 implementation it is possible to remove rte_lpm_tbl_entry.depth\n   field that helps to save 6 bits.\n - Also new dir24_8 implementation supports different next_hop sizes\n   (1/2/4/8 bytes per next hop)\n - Removed RTE_LPM_LOOKUP_SUCCESS to save 1 bit and to eleminate ternary operator.\n   Instead it returns special default value if there is no route.\n\nSigned-off-by: Medvedkin Vladimir <medvedkinv@gmail.com>\n---\n config/common_base                 |   6 +\n doc/api/doxy-api.conf              |   1 +\n lib/Makefile                       |   2 +\n lib/librte_rib/Makefile            |  22 ++\n lib/librte_rib/rte_dir24_8.c       | 482 +++++++++++++++++++++++++++++++++\n lib/librte_rib/rte_dir24_8.h       | 116 ++++++++\n lib/librte_rib/rte_rib.c           | 526 +++++++++++++++++++++++++++++++++++++\n lib/librte_rib/rte_rib.h           | 322 +++++++++++++++++++++++\n lib/librte_rib/rte_rib_version.map |  18 ++\n mk/rte.app.mk                      |   1 +\n 10 files changed, 1496 insertions(+)\n create mode 100644 lib/librte_rib/Makefile\n create mode 100644 lib/librte_rib/rte_dir24_8.c\n create mode 100644 lib/librte_rib/rte_dir24_8.h\n create mode 100644 lib/librte_rib/rte_rib.c\n create mode 100644 lib/librte_rib/rte_rib.h\n create mode 100644 lib/librte_rib/rte_rib_version.map",
    "diff": "diff --git a/config/common_base b/config/common_base\nindex ad03cf4..aceeff5 100644\n--- a/config/common_base\n+++ b/config/common_base\n@@ -679,6 +679,12 @@ CONFIG_RTE_LIBRTE_LPM=y\n CONFIG_RTE_LIBRTE_LPM_DEBUG=n\n \n #\n+# Compile librte_rib\n+#\n+CONFIG_RTE_LIBRTE_RIB=y\n+CONFIG_RTE_LIBRTE_RIB_DEBUG=n\n+\n+#\n # Compile librte_acl\n #\n CONFIG_RTE_LIBRTE_ACL=y\ndiff --git a/doc/api/doxy-api.conf b/doc/api/doxy-api.conf\nindex cda52fd..8e4f969 100644\n--- a/doc/api/doxy-api.conf\n+++ b/doc/api/doxy-api.conf\n@@ -60,6 +60,7 @@ INPUT                   = doc/api/doxy-api-index.md \\\n                           lib/librte_kvargs \\\n                           lib/librte_latencystats \\\n                           lib/librte_lpm \\\n+                          lib/librte_rib \\\n                           lib/librte_mbuf \\\n                           lib/librte_member \\\n                           lib/librte_mempool \\\ndiff --git a/lib/Makefile b/lib/Makefile\nindex ec965a6..7f2323a 100644\n--- a/lib/Makefile\n+++ b/lib/Makefile\n@@ -43,6 +43,8 @@ DIRS-$(CONFIG_RTE_LIBRTE_EFD) += librte_efd\n DEPDIRS-librte_efd := librte_eal librte_ring librte_hash\n DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm\n DEPDIRS-librte_lpm := librte_eal\n+DIRS-$(CONFIG_RTE_LIBRTE_RIB) += librte_rib\n+DEPDIRS-librte_rib := librte_eal\n DIRS-$(CONFIG_RTE_LIBRTE_ACL) += librte_acl\n DEPDIRS-librte_acl := librte_eal\n DIRS-$(CONFIG_RTE_LIBRTE_MEMBER) += librte_member\ndiff --git a/lib/librte_rib/Makefile b/lib/librte_rib/Makefile\nnew file mode 100644\nindex 0000000..cb97f02\n--- /dev/null\n+++ b/lib/librte_rib/Makefile\n@@ -0,0 +1,22 @@\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright(c) 2018 Vladimir Medvedkin <medvedkinv@gmail.com>\n+\n+include $(RTE_SDK)/mk/rte.vars.mk\n+\n+# library name\n+LIB = librte_rib.a\n+\n+CFLAGS += -O3\n+CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR)\n+\n+EXPORT_MAP := rte_rib_version.map\n+\n+LIBABIVER := 1\n+\n+# all source are stored in SRCS-y\n+SRCS-$(CONFIG_RTE_LIBRTE_RIB) := rte_rib.c rte_dir24_8.c\n+\n+# install this header file\n+SYMLINK-$(CONFIG_RTE_LIBRTE_RIB)-include := rte_rib.h rte_dir24_8.h\n+\n+include $(RTE_SDK)/mk/rte.lib.mk\ndiff --git a/lib/librte_rib/rte_dir24_8.c b/lib/librte_rib/rte_dir24_8.c\nnew file mode 100644\nindex 0000000..a12f882\n--- /dev/null\n+++ b/lib/librte_rib/rte_dir24_8.c\n@@ -0,0 +1,482 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2018 Vladimir Medvedkin <medvedkinv@gmail.com>\n+ */\n+\n+#include <stdint.h>\n+#include <stdlib.h>\n+#include <stdio.h>\n+#include <string.h>\n+#include <rte_debug.h>\n+#include <rte_malloc.h>\n+#include <rte_prefetch.h>\n+#include <rte_errno.h>\n+\n+#include <inttypes.h>\n+\n+#include <rte_memory.h>\n+#include <rte_branch_prediction.h>\n+\n+#include <rte_rib.h>\n+#include <rte_dir24_8.h>\n+\n+#define BITMAP_SLAB_BIT_SIZE_LOG2\t6\n+#define BITMAP_SLAB_BIT_SIZE\t\t(1 << BITMAP_SLAB_BIT_SIZE_LOG2)\n+#define BITMAP_SLAB_BITMASK\t\t(BITMAP_SLAB_BIT_SIZE - 1)\n+\n+#define ROUNDUP(x, y)\t RTE_ALIGN_CEIL(x, (1 << (32 - y)))\n+\n+static __rte_always_inline __attribute__((pure)) void *\n+get_tbl24_p(struct rte_dir24_8_tbl *fib, uint32_t ip)\n+{\n+\treturn (void *)&((uint8_t *)fib->tbl24)[(ip &\n+\t\tRTE_DIR24_8_TBL24_MASK) >> (8 - fib->nh_sz)];\n+}\n+\n+#define LOOKUP_FUNC(suffix, type, bulk_prefetch)\t\t\t\\\n+int rte_dir24_8_lookup_bulk_##suffix(void *fib_p, const uint32_t *ips,\t\\\n+\tuint64_t *next_hops, const unsigned n)\t\t\t\t\\\n+{\t\t\t\t\t\t\t\t\t\\\n+\tstruct rte_dir24_8_tbl *fib = (struct rte_dir24_8_tbl *)fib_p;\t\\\n+\tuint64_t tmp;\t\t\t\t\t\t\t\\\n+\tuint32_t i;\t\t\t\t\t\t\t\\\n+\tuint32_t prefetch_offset = RTE_MIN((unsigned)bulk_prefetch, n);\t\\\n+\t\t\t\t\t\t\t\t\t\\\n+\tRTE_RIB_RETURN_IF_TRUE(((fib == NULL) || (ips == NULL) ||\t\\\n+\t\t(next_hops == NULL)), -EINVAL);\t\t\t\t\\\n+\t\t\t\t\t\t\t\t\t\\\n+\tfor (i = 0; i < prefetch_offset; i++)\t\t\t\t\\\n+\t\trte_prefetch0(get_tbl24_p(fib, ips[i]));\t\t\\\n+\tfor (i = 0; i < (n - prefetch_offset); i++) {\t\t\t\\\n+\t\trte_prefetch0(get_tbl24_p(fib, ips[i + prefetch_offset])); \\\n+\t\ttmp = ((type *)fib->tbl24)[ips[i] >> 8];\t\t\\\n+\t\tif (unlikely((tmp & RTE_DIR24_8_VALID_EXT_ENT) ==\t\\\n+\t\t\tRTE_DIR24_8_VALID_EXT_ENT)) {\t\t\t\\\n+\t\t\ttmp = ((type *)fib->tbl8)[(uint8_t)ips[i] +\t\\\n+\t\t\t\t((tmp >> 1) * RTE_DIR24_8_TBL8_GRP_NUM_ENT)]; \\\n+\t\t}\t\t\t\t\t\t\t\\\n+\t\tnext_hops[i] = tmp >> 1;\t\t\t\t\\\n+\t}\t\t\t\t\t\t\t\t\\\n+\tfor (; i < n; i++) {\t\t\t\t\t\t\\\n+\t\ttmp = ((type *)fib->tbl24)[ips[i] >> 8];\t\t\\\n+\t\tif (unlikely((tmp & RTE_DIR24_8_VALID_EXT_ENT) ==\t\\\n+\t\t\tRTE_DIR24_8_VALID_EXT_ENT)) {\t\t\t\\\n+\t\t\ttmp = ((type *)fib->tbl8)[(uint8_t)ips[i] +\t\\\n+\t\t\t\t((tmp >> 1) * RTE_DIR24_8_TBL8_GRP_NUM_ENT)]; \\\n+\t\t}\t\t\t\t\t\t\t\\\n+\t\tnext_hops[i] = tmp >> 1;\t\t\t\t\\\n+\t}\t\t\t\t\t\t\t\t\\\n+\treturn 0;\t\t\t\t\t\t\t\\\n+}\t\t\t\t\t\t\t\t\t\\\n+\n+static void\n+write_to_fib(void *ptr, uint64_t val, enum rte_dir24_8_nh_sz size, int n)\n+{\n+\tint i;\n+\tuint8_t *ptr8 = (uint8_t *)ptr;\n+\tuint16_t *ptr16 = (uint16_t *)ptr;\n+\tuint32_t *ptr32 = (uint32_t *)ptr;\n+\tuint64_t *ptr64 = (uint64_t *)ptr;\n+\n+\tswitch (size) {\n+\tcase RTE_DIR24_8_1B:\n+\t\tfor (i = 0; i < n; i++)\n+\t\t\tptr8[i] = (uint8_t)val;\n+\t\tbreak;\n+\tcase RTE_DIR24_8_2B:\n+\t\tfor (i = 0; i < n; i++)\n+\t\t\tptr16[i] = (uint16_t)val;\n+\t\tbreak;\n+\tcase RTE_DIR24_8_4B:\n+\t\tfor (i = 0; i < n; i++)\n+\t\t\tptr32[i] = (uint32_t)val;\n+\t\tbreak;\n+\tcase RTE_DIR24_8_8B:\n+\t\tfor (i = 0; i < n; i++)\n+\t\t\tptr64[i] = (uint64_t)val;\n+\t\tbreak;\n+\t}\n+}\n+\n+static int\n+tbl8_get_idx(struct rte_dir24_8_tbl *fib)\n+{\n+\tuint32_t i;\n+\tint bit_idx;\n+\n+\tfor (i = 0; (i < (fib->number_tbl8s >> BITMAP_SLAB_BIT_SIZE_LOG2)) &&\n+\t\t(fib->tbl8_idxes[i] == UINT64_MAX); i++)\n+\t\t;\n+\tif (i <= (fib->number_tbl8s >> BITMAP_SLAB_BIT_SIZE_LOG2)) {\n+\t\tbit_idx = __builtin_ctzll(~fib->tbl8_idxes[i]);\n+\t\tfib->tbl8_idxes[i] |= (1ULL << bit_idx);\n+\t\treturn (i << BITMAP_SLAB_BIT_SIZE_LOG2) + bit_idx;\n+\t}\n+\treturn -ENOSPC;\n+}\n+\n+static inline void\n+tbl8_free_idx(struct rte_dir24_8_tbl *fib, int idx)\n+{\n+\tfib->tbl8_idxes[idx >> BITMAP_SLAB_BIT_SIZE_LOG2] &=\n+\t\t~(1ULL << (idx & BITMAP_SLAB_BITMASK));\n+}\n+\n+static int\n+tbl8_alloc(struct rte_dir24_8_tbl *fib, uint64_t nh)\n+{\n+\tint\ttbl8_idx;\n+\tuint8_t\t*tbl8_ptr;\n+\n+\ttbl8_idx = tbl8_get_idx(fib);\n+\tif (tbl8_idx < 0)\n+\t\treturn tbl8_idx;\n+\ttbl8_ptr = (uint8_t *)fib->tbl8 +\n+\t\t((tbl8_idx * RTE_DIR24_8_TBL8_GRP_NUM_ENT) <<\n+\t\tfib->nh_sz);\n+\t/*Init tbl8 entries with nexthop from tbl24*/\n+\twrite_to_fib((void *)tbl8_ptr, nh|\n+\t\tRTE_DIR24_8_VALID_EXT_ENT, fib->nh_sz,\n+\t\tRTE_DIR24_8_TBL8_GRP_NUM_ENT);\n+\treturn tbl8_idx;\n+}\n+\n+static void\n+tbl8_recycle(struct rte_dir24_8_tbl *fib, uint32_t ip, uint64_t tbl8_idx)\n+{\n+\tint i;\n+\tuint64_t nh;\n+\tuint8_t *ptr8;\n+\tuint16_t *ptr16;\n+\tuint32_t *ptr32;\n+\tuint64_t *ptr64;\n+\n+\tswitch (fib->nh_sz) {\n+\tcase RTE_DIR24_8_1B:\n+\t\tptr8 = &((uint8_t *)fib->tbl8)[tbl8_idx *\n+\t\t\t\tRTE_DIR24_8_TBL8_GRP_NUM_ENT];\n+\t\tnh = *ptr8;\n+\t\tfor (i = 1; i < RTE_DIR24_8_TBL8_GRP_NUM_ENT; i++) {\n+\t\t\tif (nh != ptr8[i])\n+\t\t\t\treturn;\n+\t\t}\n+\t\t((uint8_t *)fib->tbl24)[ip >> 8] =\n+\t\t\tnh & ~RTE_DIR24_8_VALID_EXT_ENT;\n+\t\tfor (i = 0; i < RTE_DIR24_8_TBL8_GRP_NUM_ENT; i++)\n+\t\t\tptr8[i] = 0;\n+\t\tbreak;\n+\tcase RTE_DIR24_8_2B:\n+\t\tptr16 = &((uint16_t *)fib->tbl8)[tbl8_idx *\n+\t\t\t\tRTE_DIR24_8_TBL8_GRP_NUM_ENT];\n+\t\tnh = *ptr16;\n+\t\tfor (i = 1; i < RTE_DIR24_8_TBL8_GRP_NUM_ENT; i++) {\n+\t\t\tif (nh != ptr16[i])\n+\t\t\t\treturn;\n+\t\t}\n+\t\t((uint16_t *)fib->tbl24)[ip >> 8] =\n+\t\t\tnh & ~RTE_DIR24_8_VALID_EXT_ENT;\n+\t\tfor (i = 0; i < RTE_DIR24_8_TBL8_GRP_NUM_ENT; i++)\n+\t\t\tptr16[i] = 0;\n+\t\tbreak;\n+\tcase RTE_DIR24_8_4B:\n+\t\tptr32 = &((uint32_t *)fib->tbl8)[tbl8_idx *\n+\t\t\t\tRTE_DIR24_8_TBL8_GRP_NUM_ENT];\n+\t\tnh = *ptr32;\n+\t\tfor (i = 1; i < RTE_DIR24_8_TBL8_GRP_NUM_ENT; i++) {\n+\t\t\tif (nh != ptr32[i])\n+\t\t\t\treturn;\n+\t\t}\n+\t\t((uint32_t *)fib->tbl24)[ip >> 8] =\n+\t\t\tnh & ~RTE_DIR24_8_VALID_EXT_ENT;\n+\t\tfor (i = 0; i < RTE_DIR24_8_TBL8_GRP_NUM_ENT; i++)\n+\t\t\tptr32[i] = 0;\n+\t\tbreak;\n+\tcase RTE_DIR24_8_8B:\n+\t\tptr64 = &((uint64_t *)fib->tbl8)[tbl8_idx *\n+\t\t\t\tRTE_DIR24_8_TBL8_GRP_NUM_ENT];\n+\t\tnh = *ptr64;\n+\t\tfor (i = 1; i < RTE_DIR24_8_TBL8_GRP_NUM_ENT; i++) {\n+\t\t\tif (nh != ptr64[i])\n+\t\t\t\treturn;\n+\t\t}\n+\t\t((uint64_t *)fib->tbl24)[ip >> 8] =\n+\t\t\tnh & ~RTE_DIR24_8_VALID_EXT_ENT;\n+\t\tfor (i = 0; i < RTE_DIR24_8_TBL8_GRP_NUM_ENT; i++)\n+\t\t\tptr64[i] = 0;\n+\t\tbreak;\n+\t}\n+\ttbl8_free_idx(fib, tbl8_idx);\n+}\n+\n+static int\n+install_to_fib(struct rte_dir24_8_tbl *fib, uint32_t ledge, uint32_t redge,\n+\tuint64_t next_hop)\n+{\n+\tuint64_t\ttbl24_tmp;\n+\tint\ttbl8_idx;\n+\tint tmp_tbl8_idx;\n+\tuint8_t\t*tbl8_ptr;\n+\n+\t/*case for 0.0.0.0/0*/\n+\tif (unlikely((ledge == 0) && (redge == 0))) {\n+\t\twrite_to_fib(fib->tbl24, next_hop << 1, fib->nh_sz, 1 << 24);\n+\t\treturn 0;\n+\t}\n+\tif (ROUNDUP(ledge, 24) <= redge) {\n+\t\tif (ledge < ROUNDUP(ledge, 24)) {\n+\t\t\ttbl24_tmp = RTE_DIR24_8_GET_TBL24(fib, ledge);\n+\t\t\tif ((tbl24_tmp & RTE_DIR24_8_VALID_EXT_ENT) !=\n+\t\t\t\tRTE_DIR24_8_VALID_EXT_ENT) {\n+\t\t\t\ttbl8_idx = tbl8_alloc(fib, tbl24_tmp);\n+\t\t\t\ttmp_tbl8_idx = tbl8_get_idx(fib);\n+\t\t\t\tif ((tbl8_idx < 0) || (tmp_tbl8_idx < 0))\n+\t\t\t\t\treturn -ENOSPC;\n+\t\t\t\ttbl8_free_idx(fib, tmp_tbl8_idx);\n+\t\t\t\t/*update dir24 entry with tbl8 index*/\n+\t\t\t\twrite_to_fib(get_tbl24_p(fib, ledge),\n+\t\t\t\t\t(tbl8_idx << 1)|\n+\t\t\t\t\tRTE_DIR24_8_VALID_EXT_ENT,\n+\t\t\t\t\tfib->nh_sz, 1);\n+\t\t\t} else\n+\t\t\t\ttbl8_idx = tbl24_tmp >> 1;\n+\t\t\ttbl8_ptr = (uint8_t *)fib->tbl8 +\n+\t\t\t\t(((tbl8_idx * RTE_DIR24_8_TBL8_GRP_NUM_ENT) +\n+\t\t\t\t(ledge & ~RTE_DIR24_8_TBL24_MASK)) <<\n+\t\t\t\tfib->nh_sz);\n+\t\t\t/*update tbl8 with new next hop*/\n+\t\t\twrite_to_fib((void *)tbl8_ptr, (next_hop << 1)|\n+\t\t\t\tRTE_DIR24_8_VALID_EXT_ENT,\n+\t\t\t\tfib->nh_sz, ROUNDUP(ledge, 24) - ledge);\n+\t\t\ttbl8_recycle(fib, ledge, tbl8_idx);\n+\t\t}\n+\t\tif (ROUNDUP(ledge, 24) < (redge & RTE_DIR24_8_TBL24_MASK)) {\n+\t\t\twrite_to_fib(get_tbl24_p(fib, ROUNDUP(ledge, 24)),\n+\t\t\t\tnext_hop << 1, fib->nh_sz,\n+\t\t\t\t((redge & RTE_DIR24_8_TBL24_MASK) -\n+\t\t\t\tROUNDUP(ledge, 24)) >> 8);\n+\t\t}\n+\t\tif (redge & ~RTE_DIR24_8_TBL24_MASK) {\n+\t\t\ttbl24_tmp = RTE_DIR24_8_GET_TBL24(fib, redge);\n+\t\t\tif ((tbl24_tmp & RTE_DIR24_8_VALID_EXT_ENT) !=\n+\t\t\t\t\tRTE_DIR24_8_VALID_EXT_ENT) {\n+\t\t\t\ttbl8_idx = tbl8_alloc(fib, tbl24_tmp);\n+\t\t\t\tif (tbl8_idx < 0)\n+\t\t\t\t\treturn -ENOSPC;\n+\t\t\t\t/*update dir24 entry with tbl8 index*/\n+\t\t\t\twrite_to_fib(get_tbl24_p(fib, redge),\n+\t\t\t\t\t(tbl8_idx << 1)|\n+\t\t\t\t\tRTE_DIR24_8_VALID_EXT_ENT,\n+\t\t\t\t\tfib->nh_sz, 1);\n+\t\t\t} else\n+\t\t\t\ttbl8_idx = tbl24_tmp >> 1;\n+\t\t\ttbl8_ptr = (uint8_t *)fib->tbl8 +\n+\t\t\t\t((tbl8_idx * RTE_DIR24_8_TBL8_GRP_NUM_ENT) <<\n+\t\t\t\tfib->nh_sz);\n+\t\t\t/*update tbl8 with new next hop*/\n+\t\t\twrite_to_fib((void *)tbl8_ptr, (next_hop << 1)|\n+\t\t\t\tRTE_DIR24_8_VALID_EXT_ENT,\n+\t\t\t\tfib->nh_sz, redge & ~RTE_DIR24_8_TBL24_MASK);\n+\t\t\ttbl8_recycle(fib, redge, tbl8_idx);\n+\t\t}\n+\t} else {\n+\t\ttbl24_tmp = RTE_DIR24_8_GET_TBL24(fib, ledge);\n+\t\tif ((tbl24_tmp & RTE_DIR24_8_VALID_EXT_ENT) !=\n+\t\t\tRTE_DIR24_8_VALID_EXT_ENT) {\n+\t\t\ttbl8_idx = tbl8_alloc(fib, tbl24_tmp);\n+\t\t\tif (tbl8_idx < 0)\n+\t\t\t\treturn -ENOSPC;\n+\t\t\t/*update dir24 entry with tbl8 index*/\n+\t\t\twrite_to_fib(get_tbl24_p(fib, ledge),\n+\t\t\t\t(tbl8_idx << 1)|\n+\t\t\t\tRTE_DIR24_8_VALID_EXT_ENT,\n+\t\t\t\tfib->nh_sz, 1);\n+\t\t} else\n+\t\t\ttbl8_idx = tbl24_tmp >> 1;\n+\t\ttbl8_ptr = (uint8_t *)fib->tbl8 +\n+\t\t\t(((tbl8_idx * RTE_DIR24_8_TBL8_GRP_NUM_ENT) +\n+\t\t\t(ledge & ~RTE_DIR24_8_TBL24_MASK)) <<\n+\t\t\tfib->nh_sz);\n+\t\t/*update tbl8 with new next hop*/\n+\t\twrite_to_fib((void *)tbl8_ptr, (next_hop << 1)|\n+\t\t\tRTE_DIR24_8_VALID_EXT_ENT,\n+\t\t\tfib->nh_sz, redge - ledge);\n+\t\ttbl8_recycle(fib, ledge, tbl8_idx);\n+\t}\n+\treturn 0;\n+}\n+\n+static int\n+modify_fib(struct rte_rib *rib, uint32_t ip, uint8_t depth,\n+\tuint64_t next_hop)\n+{\n+\tstruct rte_rib_node *tmp = NULL;\n+\tstruct rte_dir24_8_tbl *fib;\n+\tuint32_t ledge, redge;\n+\tint ret;\n+\n+\tfib = rib->fib;\n+\n+\tif (next_hop > DIR24_8_MAX_NH(fib))\n+\t\treturn -EINVAL;\n+\n+\tledge = ip;\n+\tdo {\n+\t\ttmp = rte_rib_tree_get_nxt(rib, ip, depth, tmp,\n+\t\t\tRTE_RIB_GET_NXT_COVER);\n+\t\tif (tmp != NULL) {\n+\t\t\tif (tmp->depth == depth)\n+\t\t\t\tcontinue;\n+\t\t\tredge = tmp->key;\n+\t\t\tif (ledge == redge) {\n+\t\t\t\tledge = redge +\n+\t\t\t\t\t(uint32_t)(1ULL << (32 - tmp->depth));\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tret = install_to_fib(fib, ledge, redge,\n+\t\t\t\tnext_hop);\n+\t\t\tif (ret != 0)\n+\t\t\t\treturn ret;\n+\t\t\tledge = redge +\n+\t\t\t\t(uint32_t)(1ULL << (32 - tmp->depth));\n+\t\t} else {\n+\t\t\tredge = ip + (uint32_t)(1ULL << (32 - depth));\n+\t\t\tret = install_to_fib(fib, ledge, redge,\n+\t\t\t\tnext_hop);\n+\t\t\tif (ret != 0)\n+\t\t\t\treturn ret;\n+\t\t}\n+\t} while (tmp);\n+\n+\treturn 0;\n+}\n+\n+int\n+rte_dir24_8_modify(struct rte_rib *rib, uint32_t ip, uint8_t depth,\n+\tuint64_t next_hop, enum rte_rib_op op)\n+{\n+\tstruct rte_dir24_8_tbl *fib;\n+\tstruct rte_rib_node *tmp = NULL;\n+\tstruct rte_rib_node *node;\n+\tstruct rte_rib_node *parent;\n+\tint ret = 0;\n+\n+\tif ((rib == NULL) || (depth > RTE_RIB_MAXDEPTH))\n+\t\treturn -EINVAL;\n+\n+\tfib = rib->fib;\n+\tRTE_ASSERT(fib);\n+\n+\tip &= (uint32_t)(UINT64_MAX << (32 - depth));\n+\n+\tnode = rte_rib_tree_lookup_exact(rib, ip, depth);\n+\tswitch (op) {\n+\tcase RTE_RIB_ADD:\n+\t\tif (node != NULL) {\n+\t\t\tif (node->nh == next_hop)\n+\t\t\t\treturn 0;\n+\t\t\tret = modify_fib(rib, ip, depth, next_hop);\n+\t\t\tif (ret == 0)\n+\t\t\t\tnode->nh = next_hop;\n+\t\t\treturn 0;\n+\t\t}\n+\t\tif (depth > 24) {\n+\t\t\ttmp = rte_rib_tree_get_nxt(rib, ip, 24, NULL,\n+\t\t\t\tRTE_RIB_GET_NXT_COVER);\n+\t\t\tif ((tmp == NULL) &&\n+\t\t\t\t(fib->cur_tbl8s >= fib->number_tbl8s))\n+\t\t\t\treturn -ENOSPC;\n+\n+\t\t}\n+\t\tnode = rte_rib_tree_insert(rib, ip, depth);\n+\t\tif (node == NULL)\n+\t\t\treturn -rte_errno;\n+\t\tnode->nh = next_hop;\n+\t\tparent = rte_rib_tree_lookup_parent(node);\n+\t\tif ((parent != NULL) && (parent->nh == next_hop))\n+\t\t\treturn 0;\n+\t\tret = modify_fib(rib, ip, depth, next_hop);\n+\t\tif (ret) {\n+\t\t\trte_rib_tree_remove(rib, ip, depth);\n+\t\t\treturn ret;\n+\t\t}\n+\t\tif ((depth > 24) && (tmp == NULL))\n+\t\t\tfib->cur_tbl8s++;\n+\t\treturn 0;\n+\tcase RTE_RIB_DEL:\n+\t\tif (node == NULL)\n+\t\t\treturn -ENOENT;\n+\n+\t\tparent = rte_rib_tree_lookup_parent(node);\n+\t\tif (parent != NULL) {\n+\t\t\tif (parent->nh != node->nh)\n+\t\t\t\tret = modify_fib(rib, ip, depth, parent->nh);\n+\t\t} else\n+\t\t\tret = modify_fib(rib, ip, depth, fib->def_nh);\n+\t\tif (ret == 0) {\n+\t\t\trte_rib_tree_remove(rib, ip, depth);\n+\t\t\tif (depth > 24) {\n+\t\t\t\ttmp = rte_rib_tree_get_nxt(rib, ip, 24, NULL,\n+\t\t\t\t\tRTE_RIB_GET_NXT_COVER);\n+\t\t\t\tif (tmp == NULL)\n+\t\t\t\t\tfib->cur_tbl8s--;\n+\t\t\t}\n+\t\t}\n+\t\treturn ret;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\treturn -EINVAL;\n+}\n+\n+struct rte_dir24_8_tbl *rte_dir24_8_create(const char *name, int socket_id,\n+\tenum rte_dir24_8_nh_sz nh_sz, uint64_t def_nh)\n+{\n+\tchar mem_name[RTE_RIB_NAMESIZE];\n+\tstruct rte_dir24_8_tbl *fib;\n+\n+\tsnprintf(mem_name, sizeof(mem_name), \"FIB_%s\", name);\n+\tfib = rte_zmalloc_socket(name, sizeof(struct rte_dir24_8_tbl) +\n+\t\tRTE_DIR24_8_TBL24_NUM_ENT * (1 << nh_sz), RTE_CACHE_LINE_SIZE,\n+\t\tsocket_id);\n+\tif (fib == NULL)\n+\t\treturn fib;\n+\n+\tsnprintf(mem_name, sizeof(mem_name), \"TBL8_%s\", name);\n+\tfib->tbl8 = rte_zmalloc_socket(mem_name, RTE_DIR24_8_TBL8_GRP_NUM_ENT *\n+\t\t\t(1 << nh_sz) * RTE_DIR24_8_TBL8_NUM_GROUPS,\n+\t\t\tRTE_CACHE_LINE_SIZE, socket_id);\n+\tif (fib->tbl8 == NULL) {\n+\t\trte_free(fib);\n+\t\treturn NULL;\n+\t}\n+\tfib->def_nh = def_nh;\n+\tfib->nh_sz = nh_sz;\n+\tfib->number_tbl8s = RTE_MIN((uint32_t)RTE_DIR24_8_TBL8_NUM_GROUPS,\n+\t\t\t\tDIR24_8_MAX_NH(fib));\n+\n+\tsnprintf(mem_name, sizeof(mem_name), \"TBL8_idxes_%s\", name);\n+\tfib->tbl8_idxes = rte_zmalloc_socket(mem_name,\n+\t\t\tRTE_ALIGN_CEIL(fib->number_tbl8s, 64) >> 3,\n+\t\t\tRTE_CACHE_LINE_SIZE, socket_id);\n+\tif (fib->tbl8_idxes == NULL) {\n+\t\trte_free(fib->tbl8);\n+\t\trte_free(fib);\n+\t\treturn NULL;\n+\t}\n+\n+\treturn fib;\n+}\n+\n+void\n+rte_dir24_8_free(void *fib_p)\n+{\n+\tstruct rte_dir24_8_tbl *fib = (struct rte_dir24_8_tbl *)fib_p;\n+\n+\trte_free(fib->tbl8_idxes);\n+\trte_free(fib->tbl8);\n+\trte_free(fib);\n+}\n+\n+LOOKUP_FUNC(1b, uint8_t, 5)\n+LOOKUP_FUNC(2b, uint16_t, 6)\n+LOOKUP_FUNC(4b, uint32_t, 15)\n+LOOKUP_FUNC(8b, uint64_t, 12)\ndiff --git a/lib/librte_rib/rte_dir24_8.h b/lib/librte_rib/rte_dir24_8.h\nnew file mode 100644\nindex 0000000..f779409\n--- /dev/null\n+++ b/lib/librte_rib/rte_dir24_8.h\n@@ -0,0 +1,116 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2018 Vladimir Medvedkin <medvedkinv@gmail.com>\n+ */\n+\n+#ifndef _RTE_DIR24_8_H_\n+#define _RTE_DIR24_8_H_\n+\n+/**\n+ * @file\n+ * RTE Longest Prefix Match (LPM)\n+ */\n+\n+#ifdef __cplusplus\n+extern \"C\" {\n+#endif\n+\n+/** @internal Total number of tbl24 entries. */\n+#define RTE_DIR24_8_TBL24_NUM_ENT\t(1 << 24)\n+\n+/** Maximum depth value possible for IPv4 LPM. */\n+#define RTE_DIR24_8_MAX_DEPTH\t\t32\n+\n+/** @internal Number of entries in a tbl8 group. */\n+#define RTE_DIR24_8_TBL8_GRP_NUM_ENT\t256\n+\n+/** @internal Total number of tbl8 groups in the tbl8. */\n+#define RTE_DIR24_8_TBL8_NUM_GROUPS\t65536\n+\n+/** @internal bitmask with valid and valid_group fields set */\n+#define RTE_DIR24_8_VALID_EXT_ENT\t0x01\n+\n+#define RTE_DIR24_8_TBL24_MASK\t\t0xffffff00\n+\n+/** Size of nexthop (1 << nh_sz) bits */\n+enum rte_dir24_8_nh_sz {\n+\tRTE_DIR24_8_1B,\n+\tRTE_DIR24_8_2B,\n+\tRTE_DIR24_8_4B,\n+\tRTE_DIR24_8_8B\n+};\n+\n+\n+#define DIR24_8_BITS_IN_NH(fib)\t\t(8 * (1 << fib->nh_sz))\n+#define DIR24_8_MAX_NH(fib)\t((1ULL << (DIR24_8_BITS_IN_NH(fib) - 1)) - 1)\n+\n+#define DIR24_8_TBL_IDX(a, fib)\t\t((a) >> (3 - fib->nh_sz))\n+#define DIR24_8_PSD_IDX(a, fib)\t\t((a) & ((1 << (3 - fib->nh_sz)) - 1))\n+\n+#define DIR24_8_TBL24_VAL(ip)\t(ip >> 8)\n+#define DIR24_8_TBL8_VAL(res, ip)\t\t\t\t\t\\\n+\t((res >> 1) * RTE_DIR24_8_TBL8_GRP_NUM_ENT + (uint8_t)ip)\t\\\n+\n+#define DIR24_8_LOOKUP_MSK\t\t\t\t\t\t\\\n+\t(((1ULL << ((1 << (fib->nh_sz + 3)) - 1)) << 1) - 1)\t\t\\\n+\n+#define RTE_DIR24_8_GET_TBL24(fib, ip)\t\t\t\t\t\\\n+\t((fib->tbl24[DIR24_8_TBL_IDX(DIR24_8_TBL24_VAL(ip), fib)] >>\t\\\n+\t(DIR24_8_PSD_IDX(DIR24_8_TBL24_VAL(ip), fib) *\t\t\t\\\n+\tDIR24_8_BITS_IN_NH(fib))) & DIR24_8_LOOKUP_MSK)\t\t\t\\\n+\n+#define RTE_DIR24_8_GET_TBL8(fib, res, ip)\t\t\t\t\\\n+\t((fib->tbl8[DIR24_8_TBL_IDX(DIR24_8_TBL8_VAL(res, ip), fib)] >>\t\\\n+\t(DIR24_8_PSD_IDX(DIR24_8_TBL8_VAL(res, ip), fib) *\t\t\\\n+\tDIR24_8_BITS_IN_NH(fib))) & DIR24_8_LOOKUP_MSK)\t\t\t\\\n+\n+\n+struct rte_dir24_8_tbl {\n+\tuint32_t\tnumber_tbl8s;\t/**< Total number of tbl8s. */\n+\tuint32_t\tcur_tbl8s;\t/**< Current cumber of tbl8s. */\n+\tuint64_t\tdef_nh;\n+\tenum rte_dir24_8_nh_sz\tnh_sz;\t/**< Size of nexthop entry */\n+\tuint64_t\t*tbl8;\t\t/**< LPM tbl8 table. */\n+\tuint64_t\t*tbl8_idxes;\n+\tuint64_t\ttbl24[0] __rte_cache_aligned; /**< LPM tbl24 table. */\n+};\n+\n+struct rte_dir24_8_tbl *rte_dir24_8_create(const char *name, int socket_id,\n+\tenum rte_dir24_8_nh_sz nh_sz, uint64_t def_nh);\n+void rte_dir24_8_free(void *fib_p);\n+int rte_dir24_8_modify(struct rte_rib *rib, uint32_t key,\n+\tuint8_t depth, uint64_t next_hop, enum rte_rib_op op);\n+int rte_dir24_8_lookup_bulk_1b(void *fib_p, const uint32_t *ips,\n+\tuint64_t *next_hops, const unsigned n);\n+int rte_dir24_8_lookup_bulk_2b(void *fib_p, const uint32_t *ips,\n+\tuint64_t *next_hops, const unsigned n);\n+int rte_dir24_8_lookup_bulk_4b(void *fib_p, const uint32_t *ips,\n+\tuint64_t *next_hops, const unsigned n);\n+int rte_dir24_8_lookup_bulk_8b(void *fib_p, const uint32_t *ips,\n+\tuint64_t *next_hops, const unsigned n);\n+\n+\n+static inline int\n+rte_dir24_8_lookup(void *fib_p, uint32_t ip, uint64_t *next_hop)\n+{\n+\tuint64_t res;\n+\tstruct rte_dir24_8_tbl *fib = (struct rte_dir24_8_tbl *)fib_p;\n+\n+\tRTE_RIB_RETURN_IF_TRUE(((fib == NULL) || (ip == NULL) ||\n+\t\t(next_hop == NULL)), -EINVAL);\n+\n+\tres = RTE_DIR24_8_GET_TBL24(fib, ip);\n+\tif (unlikely((res & RTE_DIR24_8_VALID_EXT_ENT) ==\n+\t\tRTE_DIR24_8_VALID_EXT_ENT)) {\n+\t\tres = RTE_DIR24_8_GET_TBL8(fib, res, ip);\n+\t}\n+\t*next_hop = res >> 1;\n+\treturn 0;\n+}\n+\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+\n+#endif /* _RTE_DIR24_8_H_ */\n+\ndiff --git a/lib/librte_rib/rte_rib.c b/lib/librte_rib/rte_rib.c\nnew file mode 100644\nindex 0000000..7783b23\n--- /dev/null\n+++ b/lib/librte_rib/rte_rib.c\n@@ -0,0 +1,526 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2018 Vladimir Medvedkin <medvedkinv@gmail.com>\n+ */\n+\n+#include <stdint.h>\n+#include <stdlib.h>\n+#include <stdio.h>\n+#include <string.h>\n+#include <sys/queue.h>\n+\n+#include <rte_eal.h>\n+#include <rte_eal_memconfig.h>\n+#include <rte_common.h>\n+#include <rte_tailq.h>\n+#include <rte_errno.h>\n+#include <rte_rwlock.h>\n+#include <rte_memory.h>\n+#include <rte_memzone.h>\n+#include <rte_mempool.h>\n+#include <rte_malloc.h>\n+#include <rte_log.h>\n+\n+#include <rte_rib.h>\n+#include <rte_dir24_8.h>\n+\n+TAILQ_HEAD(rte_rib_list, rte_tailq_entry);\n+static struct rte_tailq_elem rte_rib_tailq = {\n+\t.name = \"RTE_RIB\",\n+};\n+EAL_REGISTER_TAILQ(rte_rib_tailq)\n+\n+static struct rte_rib_node *\n+new_node_malloc(struct rte_rib *rib)\n+{\n+\tstruct rte_rib_node *ent;\n+\n+\tent =  malloc(rib->node_sz);\n+\tif (unlikely(ent == NULL))\n+\t\treturn NULL;\n+\t++rib->cur_nodes;\n+\treturn ent;\n+}\n+\n+static void\n+free_node_malloc(__rte_unused struct rte_rib *rib, struct rte_rib_node *ent)\n+{\n+\t--rib->cur_nodes;\n+\tfree(ent);\n+}\n+\n+static struct rte_rib_node *\n+new_node_mempool(struct rte_rib *rib)\n+{\n+\tstruct rte_rib_node *ent;\n+\tint ret;\n+\n+\tret = rte_mempool_get(rib->node_pool, (void *)&ent);\n+\tif (unlikely(ret != 0))\n+\t\treturn NULL;\n+\t++rib->cur_nodes;\n+\treturn ent;\n+}\n+\n+static void\n+free_node_mempool(struct rte_rib *rib, struct rte_rib_node *ent)\n+{\n+\t--rib->cur_nodes;\n+\trte_mempool_put(rib->node_pool, ent);\n+}\n+\n+struct rte_rib_node *\n+rte_rib_tree_lookup(struct rte_rib *rib, uint32_t key)\n+{\n+\tstruct rte_rib_node *cur = rib->trie;\n+\tstruct rte_rib_node *prev = NULL;\n+\n+\twhile ((cur != NULL) && (((cur->key ^ key) &\n+\t\t(uint32_t)(UINT64_MAX << (32 - cur->depth))) == 0)) {\n+\t\tif ((cur->flag & RTE_RIB_VALID_NODE) == RTE_RIB_VALID_NODE)\n+\t\t\tprev = cur;\n+\t\tcur = RTE_RIB_GET_NXT_NODE(cur, key);\n+\t}\n+\treturn prev;\n+}\n+\n+struct rte_rib_node *\n+rte_rib_tree_lookup_parent(struct rte_rib_node *ent)\n+{\n+\tstruct rte_rib_node *tmp;\n+\n+\tif (ent == NULL)\n+\t\treturn NULL;\n+\ttmp = ent->parent;\n+\twhile ((tmp != NULL) &&\n+\t\t(tmp->flag & RTE_RIB_VALID_NODE) != RTE_RIB_VALID_NODE) {\n+\t\ttmp = tmp->parent;\n+}\n+\treturn tmp;\n+}\n+\n+struct rte_rib_node *\n+rte_rib_tree_lookup_exact(struct rte_rib *rib, uint32_t key, uint8_t depth)\n+{\n+\tstruct rte_rib_node *cur = rib->trie;\n+\n+\tkey &= (uint32_t)(UINT64_MAX << (32 - depth));\n+\twhile (cur != NULL) {\n+\t\tif ((cur->key == key) && (cur->depth == depth) &&\n+\t\t\t\t(cur->flag & RTE_RIB_VALID_NODE))\n+\t\t\treturn cur;\n+\t\tif ((cur->depth > depth) ||\n+\t\t\t\t(((uint64_t)key >> (32 - cur->depth)) !=\n+\t\t\t\t((uint64_t)cur->key >> (32 - cur->depth))))\n+\t\t\tbreak;\n+\t\tcur = RTE_RIB_GET_NXT_NODE(cur, key);\n+\t}\n+\treturn NULL;\n+}\n+\n+struct rte_rib_node *\n+rte_rib_tree_get_nxt(struct rte_rib *rib, uint32_t key,\n+\tuint8_t depth, struct rte_rib_node *cur, int flag)\n+{\n+\tstruct rte_rib_node *tmp, *prev = NULL;\n+\n+\tif (cur == NULL) {\n+\t\ttmp = rib->trie;\n+\t\twhile ((tmp) && (tmp->depth < depth))\n+\t\t\ttmp = RTE_RIB_GET_NXT_NODE(tmp, key);\n+\t} else {\n+\t\ttmp = cur;\n+\t\twhile ((tmp->parent != NULL) && (RTE_RIB_IS_RIGHT_NODE(tmp) ||\n+\t\t\t\t(tmp->parent->right == NULL))) {\n+\t\t\ttmp = tmp->parent;\n+\t\t\tif ((tmp->flag & RTE_RIB_VALID_NODE) &&\n+\t\t\t\t(RTE_RIB_IS_COVERED(tmp->key, tmp->depth,\n+\t\t\t\t\tkey, depth)))\n+\t\t\t\treturn tmp;\n+\t\t}\n+\t\ttmp = (tmp->parent) ? tmp->parent->right : NULL;\n+\t}\n+\twhile (tmp) {\n+\t\tif ((tmp->flag & RTE_RIB_VALID_NODE) &&\n+\t\t\t(RTE_RIB_IS_COVERED(tmp->key, tmp->depth,\n+\t\t\t\tkey, depth))) {\n+\t\t\tprev = tmp;\n+\t\t\tif (flag == RTE_RIB_GET_NXT_COVER)\n+\t\t\t\treturn prev;\n+\t\t}\n+\t\ttmp = (tmp->left) ? tmp->left : tmp->right;\n+\t}\n+\treturn prev;\n+}\n+\n+void\n+rte_rib_tree_remove(struct rte_rib *rib, uint32_t key, uint8_t depth)\n+{\n+\tstruct rte_rib_node *cur, *prev, *child;\n+\n+\tcur = rte_rib_tree_lookup_exact(rib, key, depth);\n+\tif (cur == NULL)\n+\t\treturn;\n+\n+\t--rib->cur_routes;\n+\tcur->flag &= ~RTE_RIB_VALID_NODE;\n+\twhile ((cur->flag & RTE_RIB_VALID_NODE) != RTE_RIB_VALID_NODE) {\n+\t\tif ((cur->left != NULL) && (cur->right != NULL))\n+\t\t\treturn;\n+\t\tchild = (cur->left == NULL) ? cur->right : cur->left;\n+\t\tif (child != NULL)\n+\t\t\tchild->parent = cur->parent;\n+\t\tif (cur->parent == NULL) {\n+\t\t\trib->trie = child;\n+\t\t\trib->free_node(rib, cur);\n+\t\t\treturn;\n+\t\t}\n+\t\tif (cur->parent->left == cur)\n+\t\t\tcur->parent->left = child;\n+\t\telse\n+\t\t\tcur->parent->right = child;\n+\t\tprev = cur;\n+\t\tcur = cur->parent;\n+\t\trib->free_node(rib, prev);\n+\t}\n+}\n+\n+struct rte_rib_node *\n+rte_rib_tree_insert(struct rte_rib *rib, uint32_t key, uint8_t depth)\n+{\n+\tstruct rte_rib_node **tmp = &rib->trie;\n+\tstruct rte_rib_node *prev = NULL;\n+\tstruct rte_rib_node *new_node = NULL;\n+\tstruct rte_rib_node *common_node = NULL;\n+\tint i = 0;\n+\tuint32_t common_prefix;\n+\tuint8_t common_depth;\n+\n+\tif (depth > 32) {\n+\t\trte_errno = EINVAL;\n+\t\treturn NULL;\n+\t}\n+\n+\tkey &= (uint32_t)(UINT64_MAX << (32 - depth));\n+\tnew_node = rte_rib_tree_lookup_exact(rib, key, depth);\n+\tif (new_node != NULL) {\n+\t\trte_errno = EEXIST;\n+\t\treturn NULL;\n+\t}\n+\n+\tnew_node = rib->alloc_node(rib);\n+\tif (new_node == NULL) {\n+\t\trte_errno = ENOMEM;\n+\t\treturn NULL;\n+\t}\n+\tnew_node->left = NULL;\n+\tnew_node->right = NULL;\n+\tnew_node->parent = NULL;\n+\tnew_node->key = key;\n+\tnew_node->depth = depth;\n+\tnew_node->flag = RTE_RIB_VALID_NODE;\n+\n+\twhile (1) {\n+\t\tif (*tmp == NULL) {\n+\t\t\t*tmp = new_node;\n+\t\t\tnew_node->parent = prev;\n+\t\t}\n+\t\tif ((key == (*tmp)->key) && (depth == (*tmp)->depth)) {\n+\t\t\tif (new_node != *tmp) {\n+\t\t\t\trib->free_node(rib, new_node);\n+\t\t\t\t(*tmp)->flag |= RTE_RIB_VALID_NODE;\n+\t\t\t}\n+\t\t\t++rib->cur_routes;\n+\t\t\treturn *tmp;\n+\t\t}\n+\t\ti = (*tmp)->depth;\n+\t\tif ((i >= depth) || (((uint64_t)key >> (32 - i)) !=\n+\t\t\t\t((uint64_t)(*tmp)->key >> (32 - i))))\n+\t\t\tbreak;\n+\t\tprev = *tmp;\n+\t\ttmp = (key & (1 << (31 - i))) ? &(*tmp)->right : &(*tmp)->left;\n+\t}\n+\tcommon_depth = RTE_MIN(depth, (*tmp)->depth);\n+\tcommon_prefix = key ^ (*tmp)->key;\n+\ti = __builtin_clz(common_prefix);\n+\n+\tcommon_depth = RTE_MIN(i, common_depth);\n+\tcommon_prefix = key & (uint32_t)(UINT64_MAX << (32 - common_depth));\n+\tif ((common_prefix == key) && (common_depth == depth)) {\n+\t\tif ((*tmp)->key & (1 << (31 - depth)))\n+\t\t\tnew_node->right = *tmp;\n+\t\telse\n+\t\t\tnew_node->left = *tmp;\n+\t\tnew_node->parent = (*tmp)->parent;\n+\t\t(*tmp)->parent = new_node;\n+\t\t*tmp = new_node;\n+\t} else {\n+\t\tcommon_node = rib->alloc_node(rib);\n+\t\tif (common_node == NULL) {\n+\t\t\trib->free_node(rib, new_node);\n+\t\t\trte_errno = ENOMEM;\n+\t\t\treturn NULL;\n+\t\t}\n+\t\tcommon_node->key = common_prefix;\n+\t\tcommon_node->depth = common_depth;\n+\t\tcommon_node->flag = 0;\n+\t\tcommon_node->parent = (*tmp)->parent;\n+\t\tnew_node->parent = common_node;\n+\t\t(*tmp)->parent = common_node;\n+\t\tif ((new_node->key & (1 << (31 - common_depth))) == 0) {\n+\t\t\tcommon_node->left = new_node;\n+\t\t\tcommon_node->right = *tmp;\n+\t\t} else {\n+\t\t\tcommon_node->left = *tmp;\n+\t\t\tcommon_node->right = new_node;\n+\t\t}\n+\t\t*tmp = common_node;\n+\t}\n+\t++rib->cur_routes;\n+\treturn new_node;\n+}\n+\n+struct rte_rib *\n+rte_rib_create(const char *name, int socket_id, struct rte_rib_conf *conf)\n+{\n+\tchar mem_name[RTE_RIB_NAMESIZE];\n+\tstruct rte_rib *rib = NULL;\n+\tstruct rte_tailq_entry *te;\n+\tstruct rte_rib_list *rib_list;\n+\tstruct rte_mempool *node_pool = NULL;\n+\tenum rte_dir24_8_nh_sz dir24_8_nh_size;\n+\n+\t/* Check user arguments. */\n+\tif ((name == NULL) || (conf == NULL) || (socket_id < -1) ||\n+\t\t\t(conf->type >= RTE_RIB_TYPE_MAX) ||\n+\t\t\t(conf->alloc_type >= RTE_RIB_ALLOC_MAX) ||\n+\t\t\t(conf->max_nodes == 0) ||\n+\t\t\t(conf->node_sz < sizeof(struct rte_rib_node))) {\n+\t\trte_errno = EINVAL;\n+\t\treturn NULL;\n+\t}\n+\n+\tif (conf->alloc_type == RTE_RIB_MEMPOOL) {\n+\t\tsnprintf(mem_name, sizeof(mem_name), \"MP_%s\", name);\n+\t\tnode_pool = rte_mempool_create(mem_name, conf->max_nodes,\n+\t\t\tconf->node_sz, 0, 0, NULL, NULL, NULL, NULL,\n+\t\t\tsocket_id, 0);\n+\n+\t\tif (node_pool == NULL) {\n+\t\t\tRTE_LOG(ERR, LPM,\n+\t\t\t\t\"Can not allocate mempool for RIB %s\\n\", name);\n+\t\t\trte_errno = ENOMEM;\n+\t\t\treturn NULL;\n+\t\t}\n+\n+\t}\n+\n+\tsnprintf(mem_name, sizeof(mem_name), \"RIB_%s\", name);\n+\n+\trib_list = RTE_TAILQ_CAST(rte_rib_tailq.head, rte_rib_list);\n+\n+\trte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);\n+\t/* guarantee there's no existing */\n+\tTAILQ_FOREACH(te, rib_list, next) {\n+\t\trib = (struct rte_rib *)te->data;\n+\t\tif (strncmp(name, rib->name, RTE_RIB_NAMESIZE) == 0)\n+\t\t\tbreak;\n+\t}\n+\trib = NULL;\n+\tif (te != NULL) {\n+\t\trte_errno = EEXIST;\n+\t\tgoto exit;\n+\t}\n+\n+\t/* allocate tailq entry */\n+\tte = rte_zmalloc(\"RIB_TAILQ_ENTRY\", sizeof(*te), 0);\n+\tif (te == NULL) {\n+\t\tRTE_LOG(ERR, LPM,\n+\t\t\t\"Can not allocate tailq entry for RIB %s\\n\", name);\n+\t\trte_errno = ENOMEM;\n+\t\tgoto exit;\n+\t}\n+\n+\t/* Allocate memory to store the LPM data structures. */\n+\trib = (struct rte_rib *)rte_zmalloc_socket(mem_name,\n+\t\tsizeof(struct rte_rib),\tRTE_CACHE_LINE_SIZE, socket_id);\n+\tif (rib == NULL) {\n+\t\tRTE_LOG(ERR, LPM, \"RIB %s memory allocation failed\\n\", name);\n+\t\trte_errno = ENOMEM;\n+\t\tgoto free_te;\n+\t}\n+\tsnprintf(rib->name, sizeof(rib->name), \"%s\", name);\n+\trib->trie = NULL;\n+\trib->max_nodes = conf->max_nodes;\n+\trib->node_sz = conf->node_sz;\n+\trib->type = conf->type;\n+\trib->alloc_type = conf->alloc_type;\n+\n+\tif (conf->type <= RTE_RIB_DIR24_8_8B) {\n+\t\tswitch (conf->type) {\n+\t\tcase RTE_RIB_DIR24_8_1B:\n+\t\t\tdir24_8_nh_size = RTE_DIR24_8_1B;\n+\t\t\trib->lookup = rte_dir24_8_lookup_bulk_1b;\n+\t\t\tbreak;\n+\t\tcase RTE_RIB_DIR24_8_2B:\n+\t\t\tdir24_8_nh_size = RTE_DIR24_8_2B;\n+\t\t\trib->lookup = rte_dir24_8_lookup_bulk_2b;\n+\t\t\tbreak;\n+\t\tcase RTE_RIB_DIR24_8_4B:\n+\t\t\tdir24_8_nh_size = RTE_DIR24_8_4B;\n+\t\t\trib->lookup = rte_dir24_8_lookup_bulk_4b;\n+\t\t\tbreak;\n+\t\tcase RTE_RIB_DIR24_8_8B:\n+\t\t\tdir24_8_nh_size = RTE_DIR24_8_8B;\n+\t\t\trib->lookup = rte_dir24_8_lookup_bulk_8b;\n+\t\t\tbreak;\n+\t\tcase RTE_RIB_TYPE_MAX:\n+\t\tdefault:\n+\t\t\tRTE_LOG(ERR, LPM, \"Bad RIB %s type\\n\", name);\n+\t\t\trte_errno = EINVAL;\n+\t\t\tgoto free_rib;\n+\t\t}\n+\t\trib->fib = (void *)rte_dir24_8_create(name, socket_id,\n+\t\t\t\tdir24_8_nh_size, conf->def_nh);\n+\t\tif (rib->fib == NULL) {\n+\t\t\tRTE_LOG(ERR, LPM, \"Failed to allocate FIB %s\\n\", name);\n+\t\t\trte_errno = ENOMEM;\n+\t\t\tgoto free_rib;\n+\t\t}\n+\t\trib->modify = rte_dir24_8_modify;\n+\t}\n+\n+\tswitch (conf->alloc_type) {\n+\tcase RTE_RIB_MALLOC:\n+\t\trib->alloc_node = new_node_malloc;\n+\t\trib->free_node = free_node_malloc;\n+\t\tbreak;\n+\tcase RTE_RIB_MEMPOOL:\n+\t\trib->node_pool = node_pool;\n+\t\trib->alloc_node = new_node_mempool;\n+\t\trib->free_node = free_node_mempool;\n+\t\tbreak;\n+\tcase RTE_RIB_ALLOC_MAX:\n+\tdefault:\n+\t\tRTE_LOG(ERR, LPM, \"Bad RIB %s alloc type\\n\", name);\n+\t\trte_errno = EINVAL;\n+\t\tgoto free_fib;\n+\t}\n+\n+\tte->data = (void *)rib;\n+\tTAILQ_INSERT_TAIL(rib_list, te, next);\n+\n+\trte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);\n+\n+\treturn rib;\n+\n+free_fib:\n+\tswitch (conf->type) {\n+\tcase RTE_RIB_DIR24_8_1B:\n+\tcase RTE_RIB_DIR24_8_2B:\n+\tcase RTE_RIB_DIR24_8_4B:\n+\tcase RTE_RIB_DIR24_8_8B:\n+\t\trte_dir24_8_free(rib->fib);\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+free_rib:\n+\trte_free(rib);\n+free_te:\n+\trte_free(te);\n+exit:\n+\tif (conf->alloc_type == RTE_RIB_MEMPOOL)\n+\t\trte_mempool_free(node_pool);\n+\trte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);\n+\n+\treturn NULL;\n+}\n+\n+struct rte_rib *\n+rte_rib_find_existing(const char *name)\n+{\n+\tstruct rte_rib *rib = NULL;\n+\tstruct rte_tailq_entry *te;\n+\tstruct rte_rib_list *rib_list;\n+\n+\trib_list = RTE_TAILQ_CAST(rte_rib_tailq.head, rte_rib_list);\n+\n+\trte_rwlock_read_lock(RTE_EAL_TAILQ_RWLOCK);\n+\tTAILQ_FOREACH(te, rib_list, next) {\n+\t\trib = (struct rte_rib *) te->data;\n+\t\tif (strncmp(name, rib->name, RTE_RIB_NAMESIZE) == 0)\n+\t\t\tbreak;\n+\t}\n+\trte_rwlock_read_unlock(RTE_EAL_TAILQ_RWLOCK);\n+\n+\tif (te == NULL) {\n+\t\trte_errno = ENOENT;\n+\t\treturn NULL;\n+\t}\n+\n+\treturn rib;\n+}\n+\n+void\n+rte_rib_free(struct rte_rib *rib)\n+{\n+\tstruct rte_tailq_entry *te;\n+\tstruct rte_rib_list *rib_list;\n+\tstruct rte_rib_node *tmp = NULL;\n+\n+\tif (rib == NULL)\n+\t\treturn;\n+\n+\trib_list = RTE_TAILQ_CAST(rte_rib_tailq.head, rte_rib_list);\n+\n+\trte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);\n+\n+\t/* find our tailq entry */\n+\tTAILQ_FOREACH(te, rib_list, next) {\n+\t\tif (te->data == (void *)rib)\n+\t\t\tbreak;\n+\t}\n+\tif (te != NULL)\n+\t\tTAILQ_REMOVE(rib_list, te, next);\n+\n+\trte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);\n+\n+\twhile ((tmp = rte_rib_tree_get_nxt(rib, 0, 0, tmp,\n+\t\tRTE_RIB_GET_NXT_ALL)) != NULL)\n+\t\trte_rib_tree_remove(rib, tmp->key, tmp->depth);\n+\n+\tif (rib->alloc_type == RTE_RIB_MEMPOOL)\n+\t\trte_mempool_free(rib->node_pool);\n+\n+\tswitch (rib->type) {\n+\tcase RTE_RIB_DIR24_8_1B:\n+\tcase RTE_RIB_DIR24_8_2B:\n+\tcase RTE_RIB_DIR24_8_4B:\n+\tcase RTE_RIB_DIR24_8_8B:\n+\t\trte_dir24_8_free(rib->fib);\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\trte_free(rib);\n+\trte_free(te);\n+}\n+\n+int\n+rte_rib_add(struct rte_rib *rib, uint32_t ip, uint8_t depth, uint64_t next_hop)\n+{\n+\tif ((rib == NULL) || (depth > RTE_RIB_MAXDEPTH))\n+\t\treturn -EINVAL;\n+\n+\treturn rib->modify(rib, ip, depth, next_hop, RTE_RIB_ADD);\n+}\n+\n+int\n+rte_rib_delete(struct rte_rib *rib, uint32_t ip, uint8_t depth)\n+{\n+\tif ((rib == NULL) || (depth > RTE_RIB_MAXDEPTH))\n+\t\treturn -EINVAL;\n+\n+\treturn rib->modify(rib, ip, depth, 0, RTE_RIB_DEL);\n+}\ndiff --git a/lib/librte_rib/rte_rib.h b/lib/librte_rib/rte_rib.h\nnew file mode 100644\nindex 0000000..6eac8fb\n--- /dev/null\n+++ b/lib/librte_rib/rte_rib.h\n@@ -0,0 +1,322 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2018 Vladimir Medvedkin <medvedkinv@gmail.com>\n+ */\n+\n+#ifndef _RTE_RIB_H_\n+#define _RTE_RIB_H_\n+\n+/**\n+ * @file\n+ * Compressed trie implementation for Longest Prefix Match\n+ */\n+\n+/** @internal Macro to enable/disable run-time checks. */\n+#if defined(RTE_LIBRTE_RIB_DEBUG)\n+#define RTE_RIB_RETURN_IF_TRUE(cond, retval) do {\t\\\n+\tif (cond)\t\t\t\t\t\\\n+\t\treturn retval;\t\t\t\t\\\n+} while (0)\n+#else\n+#define RTE_RIB_RETURN_IF_TRUE(cond, retval)\n+#endif\n+\n+#define RTE_RIB_VALID_NODE\t1\n+#define RTE_RIB_GET_NXT_ALL\t0\n+#define RTE_RIB_GET_NXT_COVER\t1\n+\n+#define RTE_RIB_INVALID_ROUTE\t0\n+#define RTE_RIB_VALID_ROUTE\t1\n+\n+/** Max number of characters in RIB name. */\n+#define RTE_RIB_NAMESIZE\t64\n+\n+/** Maximum depth value possible for IPv4 RIB. */\n+#define RTE_RIB_MAXDEPTH\t32\n+\n+/**\n+ * Macro to check if prefix1 {key1/depth1}\n+ * is covered by prefix2 {key2/depth2}\n+ */\n+#define RTE_RIB_IS_COVERED(key1, depth1, key2, depth2)\t\t\t\\\n+\t((((key1 ^ key2) & (uint32_t)(UINT64_MAX << (32 - depth2))) == 0)\\\n+\t\t&& (depth1 > depth2))\n+\n+/** @internal Macro to get next node in tree*/\n+#define RTE_RIB_GET_NXT_NODE(node, key)\t\t\t\t\t\\\n+\t((key & (1 << (31 - node->depth))) ? node->right : node->left)\n+/** @internal Macro to check if node is right child*/\n+#define RTE_RIB_IS_RIGHT_NODE(node)\t(node->parent->right == node)\n+\n+\n+struct rte_rib_node {\n+\tstruct rte_rib_node *left;\n+\tstruct rte_rib_node *right;\n+\tstruct rte_rib_node *parent;\n+\tuint32_t\tkey;\n+\tuint8_t\t\tdepth;\n+\tuint8_t\t\tflag;\n+\tuint64_t\tnh;\n+\tuint64_t\text[0];\n+};\n+\n+struct rte_rib;\n+\n+/** Type of FIB struct*/\n+enum rte_rib_type {\n+\tRTE_RIB_DIR24_8_1B,\n+\tRTE_RIB_DIR24_8_2B,\n+\tRTE_RIB_DIR24_8_4B,\n+\tRTE_RIB_DIR24_8_8B,\n+\tRTE_RIB_TYPE_MAX\n+};\n+\n+enum rte_rib_op {\n+\tRTE_RIB_ADD,\n+\tRTE_RIB_DEL\n+};\n+\n+/** RIB nodes allocation type */\n+enum rte_rib_alloc_type {\n+\tRTE_RIB_MALLOC,\n+\tRTE_RIB_MEMPOOL,\n+\tRTE_RIB_ALLOC_MAX\n+};\n+\n+typedef int (*rte_rib_modify_fn_t)(struct rte_rib *rib, uint32_t key,\n+\tuint8_t depth, uint64_t next_hop, enum rte_rib_op op);\n+typedef int (*rte_rib_tree_lookup_fn_t)(void *fib, const uint32_t *ips,\n+\tuint64_t *next_hops, const unsigned n);\n+typedef struct rte_rib_node *(*rte_rib_alloc_node_fn_t)(struct rte_rib *rib);\n+typedef void (*rte_rib_free_node_fn_t)(struct rte_rib *rib,\n+\tstruct rte_rib_node *node);\n+\n+struct rte_rib {\n+\tchar name[RTE_RIB_NAMESIZE];\n+\t/*pointer to rib trie*/\n+\tstruct rte_rib_node\t*trie;\n+\t/*pointer to dataplane struct*/\n+\tvoid\t*fib;\n+\t/*prefix modification*/\n+\trte_rib_modify_fn_t\tmodify;\n+\t/* Bulk lookup fn*/\n+\trte_rib_tree_lookup_fn_t\tlookup;\n+\t/*alloc trie element*/\n+\trte_rib_alloc_node_fn_t\talloc_node;\n+\t/*free trie element*/\n+\trte_rib_free_node_fn_t\tfree_node;\n+\tstruct rte_mempool\t*node_pool;\n+\tuint32_t\t\tcur_nodes;\n+\tuint32_t\t\tcur_routes;\n+\tint\t\t\tmax_nodes;\n+\tint\t\t\tnode_sz;\n+\tenum rte_rib_type\ttype;\n+\tenum rte_rib_alloc_type\talloc_type;\n+};\n+\n+/** RIB configuration structure */\n+struct rte_rib_conf {\n+\tenum rte_rib_type\ttype;\n+\tenum rte_rib_alloc_type\talloc_type;\n+\tint\tmax_nodes;\n+\tsize_t\tnode_sz;\n+\tuint64_t def_nh;\n+};\n+\n+/**\n+ * Lookup an IP into the RIB structure\n+ *\n+ * @param rib\n+ *  RIB object handle\n+ * @param key\n+ *  IP to be looked up in the RIB\n+ * @return\n+ *  pointer to struct rte_rib_node on success,\n+ *  NULL otherwise\n+ */\n+struct rte_rib_node *\n+rte_rib_tree_lookup(struct rte_rib *rib, uint32_t key);\n+\n+/**\n+ * Lookup less specific route into the RIB structure\n+ *\n+ * @param ent\n+ *  Pointer to struct rte_rib_node that represents target route\n+ * @return\n+ *  pointer to struct rte_rib_node that represents\n+ *  less specific route on success,\n+ *  NULL otherwise\n+ */\n+struct rte_rib_node *\n+rte_rib_tree_lookup_parent(struct rte_rib_node *ent);\n+\n+/**\n+ * Lookup prefix into the RIB structure\n+ *\n+ * @param rib\n+ *  RIB object handle\n+ * @param key\n+ *  net to be looked up in the RIB\n+ * @param depth\n+ *  prefix length\n+ * @return\n+ *  pointer to struct rte_rib_node on success,\n+ *  NULL otherwise\n+ */\n+struct rte_rib_node *\n+rte_rib_tree_lookup_exact(struct rte_rib *rib, uint32_t key, uint8_t depth);\n+\n+/**\n+ * Retrieve next more specific prefix from the RIB\n+ * that is covered by key/depth supernet\n+ *\n+ * @param rib\n+ *  RIB object handle\n+ * @param key\n+ *  net address of supernet prefix that covers returned more specific prefixes\n+ * @param depth\n+ *  supernet prefix length\n+ * @param cur\n+ *   pointer to the last returned prefix to get next prefix\n+ *   or\n+ *   NULL to get first more specific prefix\n+ * @param flag\n+ *  -RTE_RIB_GET_NXT_ALL\n+ *   get all prefixes from subtrie\n+ *  -RTE_RIB_GET_NXT_COVER\n+ *   get only first more specific prefix even if it have more specifics\n+ * @return\n+ *  pointer to the next more specific prefix\n+ *  or\n+ *  NULL if there is no prefixes left\n+ */\n+struct rte_rib_node *\n+rte_rib_tree_get_nxt(struct rte_rib *rib, uint32_t key, uint8_t depth,\n+\tstruct rte_rib_node *cur, int flag);\n+\n+/**\n+ * Remove prefix from the RIB\n+ *\n+ * @param rib\n+ *  RIB object handle\n+ * @param key\n+ *  net to be removed from the RIB\n+ * @param depth\n+ *  prefix length\n+ */\n+void\n+rte_rib_tree_remove(struct rte_rib *rib, uint32_t key, uint8_t depth);\n+\n+/**\n+ * Insert prefix into the RIB\n+ *\n+ * @param rib\n+ *  RIB object handle\n+ * @param key\n+ *  net to be inserted to the RIB\n+ * @param depth\n+ *  prefix length\n+ * @return\n+ *  pointer to new rte_rib_node on success\n+ *  NULL otherwise\n+ */\n+struct rte_rib_node *\n+rte_rib_tree_insert(struct rte_rib *rib, uint32_t key, uint8_t depth);\n+\n+/**\n+ * Create RIB\n+ *\n+ * @param name\n+ *  RIB name\n+ * @param socket_id\n+ *  NUMA socket ID for RIB table memory allocation\n+ * @param conf\n+ *  Structure containing the configuration\n+ * @return\n+ *  Handle to RIB object on success\n+ *  NULL otherwise with rte_errno set to an appropriate values.\n+ */\n+struct rte_rib *\n+rte_rib_create(const char *name, int socket_id, struct rte_rib_conf *conf);\n+\n+/**\n+ * Find an existing RIB object and return a pointer to it.\n+ *\n+ * @param name\n+ *  Name of the rib object as passed to rte_rib_create()\n+ * @return\n+ *  Pointer to rib object or NULL if object not found with rte_errno\n+ *  set appropriately. Possible rte_errno values include:\n+ *   - ENOENT - required entry not available to return.\n+ */\n+struct rte_rib *\n+rte_rib_find_existing(const char *name);\n+\n+/**\n+ * Free an RIB object.\n+ *\n+ * @param rib\n+ *   RIB object handle\n+ * @return\n+ *   None\n+ */\n+void\n+rte_rib_free(struct rte_rib *rib);\n+\n+/**\n+ * Add a rule to the RIB.\n+ *\n+ * @param rib\n+ *   RIB object handle\n+ * @param ip\n+ *   IP of the rule to be added to the RIB\n+ * @param depth\n+ *   Depth of the rule to be added to the RIB\n+ * @param next_hop\n+ *   Next hop of the rule to be added to the RIB\n+ * @return\n+ *   0 on success, negative value otherwise\n+ */\n+int\n+rte_rib_add(struct rte_rib *rib, uint32_t ip, uint8_t depth, uint64_t next_hop);\n+\n+/**\n+ * Delete a rule from the RIB.\n+ *\n+ * @param rib\n+ *   RIB object handle\n+ * @param ip\n+ *   IP of the rule to be deleted from the RIB\n+ * @param depth\n+ *   Depth of the rule to be deleted from the RIB\n+ * @return\n+ *   0 on success, negative value otherwise\n+ */\n+int\n+rte_rib_delete(struct rte_rib *rib, uint32_t ip, uint8_t depth);\n+\n+/**\n+ * Lookup multiple IP addresses in an FIB. This may be implemented as a\n+ * macro, so the address of the function should not be used.\n+ *\n+ * @param RIB\n+ *   RIB object handle\n+ * @param ips\n+ *   Array of IPs to be looked up in the FIB\n+ * @param next_hops\n+ *   Next hop of the most specific rule found for IP.\n+ *   This is an array of eight byte values.\n+ *   If the lookup for the given IP failed, then corresponding element would\n+ *   contain default value, see description of then next parameter.\n+ * @param n\n+ *   Number of elements in ips (and next_hops) array to lookup. This should be a\n+ *   compile time constant, and divisible by 8 for best performance.\n+ * @param defv\n+ *   Default value to populate into corresponding element of hop[] array,\n+ *   if lookup would fail.\n+ *  @return\n+ *   -EINVAL for incorrect arguments, otherwise 0\n+ */\n+#define rte_rib_fib_lookup_bulk(rib, ips, next_hops, n)\t\\\n+\trib->lookup(rib->fib, ips, next_hops, n)\n+\n+#endif /* _RTE_RIB_H_ */\ndiff --git a/lib/librte_rib/rte_rib_version.map b/lib/librte_rib/rte_rib_version.map\nnew file mode 100644\nindex 0000000..b193d6c\n--- /dev/null\n+++ b/lib/librte_rib/rte_rib_version.map\n@@ -0,0 +1,18 @@\n+DPDK_17.08 {\n+\tglobal:\n+\n+\trte_rib_create;\n+\trte_rib_free;\n+\trte_rib_tree_lookup;\n+\trte_rib_tree_lookup_parent;\n+\trte_rib_tree_lookup_exact;\n+\trte_rib_tree_get_nxt;\n+\trte_rib_tree_remove;\n+\trte_rib_tree_insert;\n+\trte_rib_find_existing;\n+\trte_rib_add;\n+\trte_rib_delete;\n+\trte_rib_delete_all;\n+\n+\tlocal: *;\n+};\ndiff --git a/mk/rte.app.mk b/mk/rte.app.mk\nindex 3eb41d1..4708aa4 100644\n--- a/mk/rte.app.mk\n+++ b/mk/rte.app.mk\n@@ -70,6 +70,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_GRO)            += -lrte_gro\n _LDLIBS-$(CONFIG_RTE_LIBRTE_GSO)            += -lrte_gso\n _LDLIBS-$(CONFIG_RTE_LIBRTE_METER)          += -lrte_meter\n _LDLIBS-$(CONFIG_RTE_LIBRTE_LPM)            += -lrte_lpm\n+_LDLIBS-$(CONFIG_RTE_LIBRTE_RIB)            += -lrte_rib\n # librte_acl needs --whole-archive because of weak functions\n _LDLIBS-$(CONFIG_RTE_LIBRTE_ACL)            += --whole-archive\n _LDLIBS-$(CONFIG_RTE_LIBRTE_ACL)            += -lrte_acl\n",
    "prefixes": [
        "dpdk-dev",
        "v2",
        "1/2"
    ]
}