get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 44826,
    "url": "http://patches.dpdk.org/api/patches/44826/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20180918105717.3EB045B34@dpdk.org/",
    "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": "<20180918105717.3EB045B34@dpdk.org>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20180918105717.3EB045B34@dpdk.org",
    "date": "2018-09-18T10:57:09",
    "name": "[v7,1/2] librte_lpm: Improve performance of the delete and add functions",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "cddea7fb03381fc58cc021416e4a806c82bc6d04",
    "submitter": {
        "id": 1036,
        "url": "http://patches.dpdk.org/api/people/1036/?format=api",
        "name": "Alex Kiselev",
        "email": "alex@therouter.net"
    },
    "delegate": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20180918105717.3EB045B34@dpdk.org/mbox/",
    "series": [
        {
            "id": 1367,
            "url": "http://patches.dpdk.org/api/series/1367/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=1367",
            "date": "2018-09-18T10:57:09",
            "name": "[v7,1/2] librte_lpm: Improve performance of the delete and add functions",
            "version": 7,
            "mbox": "http://patches.dpdk.org/series/1367/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/44826/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/44826/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 3EB045B34;\n\tTue, 18 Sep 2018 12:57:17 +0200 (CEST)",
            "from relay-out4.mail.masterhost.ru (relay-out4.mail.masterhost.ru\n\t[83.222.12.14]) by dpdk.org (Postfix) with ESMTP id 38CFF5B2E\n\tfor <dev@dpdk.org>; Tue, 18 Sep 2018 12:57:16 +0200 (CEST)",
            "from [37.139.80.50] (helo=h5.therouter.net)\n\tby relay4.mail.masterhost.ru with esmtpa \n\tenvelope from <alex@therouter.net>\n\tauthenticated with alex@therouter.net\n\tmessage id 1g2Dgr-0003LW-Ed; Tue, 18 Sep 2018 13:57:11 +0300",
            "by h5.therouter.net (sSMTP sendmail emulation);\n\tTue, 18 Sep 2018 13:57:09 +0300"
        ],
        "Date": "Tue, 18 Sep 2018 13:57:09 +0300",
        "To": "\"dev@dpdk.org\" <dev@dpdk.org>,\n\tBruce Richardson <bruce.richardson@intel.com>,\n\tStephen Hemminger <stephen@networkplumber.org>",
        "From": "Alex Kiselev <alex@therouter.net>",
        "X-KLMS-Rule-ID": "1",
        "X-KLMS-Message-Action": "clean",
        "X-KLMS-AntiSpam-Lua-Profiles": "128975 [Sep 18 2018]",
        "X-KLMS-AntiSpam-Version": "5.8.3.0",
        "X-KLMS-AntiSpam-Envelope-From": "alex@therouter.net",
        "X-KLMS-AntiSpam-Rate": "0",
        "X-KLMS-AntiSpam-Status": "not_detected",
        "X-KLMS-AntiSpam-Method": "none",
        "X-KLMS-AntiSpam-Info": "LuaCore: 199 199\n\tc524e2367ecb0510dd40ed0f0677dbf1650d9f24, {rep_avail},\n\t{msgid_missed_heavy}, DmarcAF: none",
        "X-MS-Exchange-Organization-SCL": "-1",
        "X-KLMS-AntiSpam-Interceptor-Info": "scan successful",
        "X-KLMS-AntiPhishing": "not scanned, disabled by settings",
        "X-KLMS-AntiVirus": "Kaspersky Security for Linux Mail Server, version 8.0.2.16,\n\tnot scanned, license restriction",
        "Subject": "[dpdk-dev] [PATCH v7 1/2] librte_lpm: Improve performance of the\n\tdelete and add functions",
        "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://mails.dpdk.org/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>",
        "Message-Id": "<20180918105717.3EB045B34@dpdk.org>"
    },
    "content": "lpm6: store rules in hash table for lpm6\n\nRework the lpm6 rule subsystem and replace\ncurrent rules algorithm complexity O(n)\nwith hashtables which allow dealing with\nlarge (50k) rule sets.\n\nSigned-off-by: Alex Kiselev <alex@therouter.net>\nAcked-by: Bruce Richardson <bruce.richardson@intel.com>\n---\n lib/Makefile               |   2 +-\n lib/librte_lpm/Makefile    |   2 +-\n lib/librte_lpm/meson.build |   1 +\n lib/librte_lpm/rte_lpm6.c  | 368 +++++++++++++++++++++++++--------------------\n 4 files changed, 210 insertions(+), 163 deletions(-)",
    "diff": "diff --git a/lib/Makefile b/lib/Makefile\nindex d82462ba2..070104657 100644\n--- a/lib/Makefile\n+++ b/lib/Makefile\n@@ -47,7 +47,7 @@ DEPDIRS-librte_hash := librte_eal librte_ring\n 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+DEPDIRS-librte_lpm := librte_eal librte_hash\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_lpm/Makefile b/lib/librte_lpm/Makefile\nindex 482bd72e9..a7946a1c5 100644\n--- a/lib/librte_lpm/Makefile\n+++ b/lib/librte_lpm/Makefile\n@@ -8,7 +8,7 @@ LIB = librte_lpm.a\n \n CFLAGS += -O3\n CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR)\n-LDLIBS += -lrte_eal\n+LDLIBS += -lrte_eal -lrte_hash\n \n EXPORT_MAP := rte_lpm_version.map\n \ndiff --git a/lib/librte_lpm/meson.build b/lib/librte_lpm/meson.build\nindex 067849427..a5176d8ae 100644\n--- a/lib/librte_lpm/meson.build\n+++ b/lib/librte_lpm/meson.build\n@@ -7,3 +7,4 @@ headers = files('rte_lpm.h', 'rte_lpm6.h')\n # since header files have different names, we can install all vector headers\n # without worrying about which architecture we actually need\n headers += files('rte_lpm_altivec.h', 'rte_lpm_neon.h', 'rte_lpm_sse.h')\n+deps += ['hash']\ndiff --git a/lib/librte_lpm/rte_lpm6.c b/lib/librte_lpm/rte_lpm6.c\nindex 149677eb1..d86e878bc 100644\n--- a/lib/librte_lpm/rte_lpm6.c\n+++ b/lib/librte_lpm/rte_lpm6.c\n@@ -21,6 +21,9 @@\n #include <rte_errno.h>\n #include <rte_rwlock.h>\n #include <rte_spinlock.h>\n+#include <rte_hash.h>\n+#include <assert.h>\n+#include <rte_jhash.h>\n \n #include \"rte_lpm6.h\"\n \n@@ -37,6 +40,8 @@\n #define BYTE_SIZE                                 8\n #define BYTES2_SIZE                              16\n \n+#define RULE_HASH_TABLE_EXTRA_SPACE              64\n+\n #define lpm6_tbl8_gindex next_hop\n \n /** Flags for setting an entry as valid/invalid. */\n@@ -70,6 +75,12 @@ struct rte_lpm6_rule {\n \tuint8_t depth; /**< Rule depth. */\n };\n \n+/** Rules tbl entry key. */\n+struct rte_lpm6_rule_key {\n+\tuint8_t ip[RTE_LPM6_IPV6_ADDR_SIZE]; /**< Rule IP address. */\n+\tuint8_t depth; /**< Rule depth. */\n+};\n+\n /** LPM6 structure. */\n struct rte_lpm6 {\n \t/* LPM metadata. */\n@@ -80,7 +91,7 @@ struct rte_lpm6 {\n \tuint32_t next_tbl8;              /**< Next tbl8 to be used. */\n \n \t/* LPM Tables. */\n-\tstruct rte_lpm6_rule *rules_tbl; /**< LPM rules. */\n+\tstruct rte_hash *rules_tbl; /**< LPM rules. */\n \tstruct rte_lpm6_tbl_entry tbl24[RTE_LPM6_TBL24_NUM_ENTRIES]\n \t\t\t__rte_cache_aligned; /**< LPM tbl24 table. */\n \tstruct rte_lpm6_tbl_entry tbl8[0]\n@@ -93,22 +104,69 @@ struct rte_lpm6 {\n  * and set the rest to 0.\n  */\n static inline void\n-mask_ip(uint8_t *ip, uint8_t depth)\n+ip6_mask_addr(uint8_t *ip, uint8_t depth)\n {\n-        int16_t part_depth, mask;\n-        int i;\n+\tint16_t part_depth, mask;\n+\tint i;\n \n-\t\tpart_depth = depth;\n+\tpart_depth = depth;\n \n-\t\tfor (i = 0; i < RTE_LPM6_IPV6_ADDR_SIZE; i++) {\n-\t\t\tif (part_depth < BYTE_SIZE && part_depth >= 0) {\n-\t\t\t\tmask = (uint16_t)(~(UINT8_MAX >> part_depth));\n-\t\t\t\tip[i] = (uint8_t)(ip[i] & mask);\n-\t\t\t} else if (part_depth < 0) {\n-\t\t\t\tip[i] = 0;\n-\t\t\t}\n-\t\t\tpart_depth -= BYTE_SIZE;\n-\t\t}\n+\tfor (i = 0; i < RTE_LPM6_IPV6_ADDR_SIZE; i++) {\n+\t\tif (part_depth < BYTE_SIZE && part_depth >= 0) {\n+\t\t\tmask = (uint16_t)(~(UINT8_MAX >> part_depth));\n+\t\t\tip[i] = (uint8_t)(ip[i] & mask);\n+\t\t} else if (part_depth < 0)\n+\t\t\tip[i] = 0;\n+\n+\t\tpart_depth -= BYTE_SIZE;\n+\t}\n+}\n+\n+/* copy ipv6 address */\n+static inline void\n+ip6_copy_addr(uint8_t *dst, const uint8_t *src)\n+{\n+\trte_memcpy(dst, src, RTE_LPM6_IPV6_ADDR_SIZE);\n+}\n+\n+/*\n+ * LPM6 rule hash function\n+ *\n+ * It's used as a hash function for the rte_hash\n+ *\tcontaining rules\n+ */\n+static inline uint32_t\n+rule_hash(const void *data, __rte_unused uint32_t data_len,\n+\t\t  uint32_t init_val)\n+{\n+\treturn rte_jhash(data, sizeof(struct rte_lpm6_rule_key), init_val);\n+}\n+\n+/*\n+ * Init a rule key.\n+ *\t  note that ip must be already masked\n+ */\n+static inline void\n+rule_key_init(struct rte_lpm6_rule_key *key, uint8_t *ip, uint8_t depth)\n+{\n+\tip6_copy_addr(key->ip, ip);\n+\tkey->depth = depth;\n+}\n+\n+/*\n+ * Rebuild the entire LPM tree by reinserting all rules\n+ */\n+static void\n+rebuild_lpm(struct rte_lpm6 *lpm)\n+{\n+\tuint64_t next_hop;\n+\tstruct rte_lpm6_rule_key *rule_key;\n+\tuint32_t iter = 0;\n+\n+\twhile (rte_hash_iterate(lpm->rules_tbl, (void *) &rule_key,\n+\t\t\t(void **) &next_hop, &iter) >= 0)\n+\t\trte_lpm6_add(lpm, rule_key->ip, rule_key->depth,\n+\t\t\t(uint32_t) next_hop);\n }\n \n /*\n@@ -121,8 +179,9 @@ rte_lpm6_create(const char *name, int socket_id,\n \tchar mem_name[RTE_LPM6_NAMESIZE];\n \tstruct rte_lpm6 *lpm = NULL;\n \tstruct rte_tailq_entry *te;\n-\tuint64_t mem_size, rules_size;\n+\tuint64_t mem_size;\n \tstruct rte_lpm6_list *lpm_list;\n+\tstruct rte_hash *rules_tbl = NULL;\n \n \tlpm_list = RTE_TAILQ_CAST(rte_lpm6_tailq.head, rte_lpm6_list);\n \n@@ -136,12 +195,32 @@ rte_lpm6_create(const char *name, int socket_id,\n \t\treturn NULL;\n \t}\n \n+\t/* create rules hash table */\n+\tsnprintf(mem_name, sizeof(mem_name), \"LRH_%s\", name);\n+\tstruct rte_hash_parameters rule_hash_tbl_params = {\n+\t\t.entries = config->max_rules * 1.2 +\n+\t\t\tRULE_HASH_TABLE_EXTRA_SPACE,\n+\t\t.key_len = sizeof(struct rte_lpm6_rule_key),\n+\t\t.hash_func = rule_hash,\n+\t\t.hash_func_init_val = 0,\n+\t\t.name = mem_name,\n+\t\t.reserved = 0,\n+\t\t.socket_id = socket_id,\n+\t\t.extra_flag = 0\n+\t};\n+\n+\trules_tbl = rte_hash_create(&rule_hash_tbl_params);\n+\tif (rules_tbl == NULL) {\n+\t\tRTE_LOG(ERR, LPM, \"LPM rules hash table allocation failed: %s (%d)\",\n+\t\t\t\t  rte_strerror(rte_errno), rte_errno);\n+\t\tgoto fail_wo_unlock;\n+\t}\n+\n \tsnprintf(mem_name, sizeof(mem_name), \"LPM_%s\", name);\n \n \t/* Determine the amount of memory to allocate. */\n \tmem_size = sizeof(*lpm) + (sizeof(lpm->tbl8[0]) *\n \t\t\tRTE_LPM6_TBL8_GROUP_NUM_ENTRIES * config->number_tbl8s);\n-\trules_size = sizeof(struct rte_lpm6_rule) * config->max_rules;\n \n \trte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);\n \n@@ -154,7 +233,7 @@ rte_lpm6_create(const char *name, int socket_id,\n \tlpm = NULL;\n \tif (te != NULL) {\n \t\trte_errno = EEXIST;\n-\t\tgoto exit;\n+\t\tgoto fail;\n \t}\n \n \t/* allocate tailq entry */\n@@ -162,7 +241,7 @@ rte_lpm6_create(const char *name, int socket_id,\n \tif (te == NULL) {\n \t\tRTE_LOG(ERR, LPM, \"Failed to allocate tailq entry!\\n\");\n \t\trte_errno = ENOMEM;\n-\t\tgoto exit;\n+\t\tgoto fail;\n \t}\n \n \t/* Allocate memory to store the LPM data structures. */\n@@ -173,34 +252,28 @@ rte_lpm6_create(const char *name, int socket_id,\n \t\tRTE_LOG(ERR, LPM, \"LPM memory allocation failed\\n\");\n \t\trte_free(te);\n \t\trte_errno = ENOMEM;\n-\t\tgoto exit;\n-\t}\n-\n-\tlpm->rules_tbl = rte_zmalloc_socket(NULL,\n-\t\t\t(size_t)rules_size, RTE_CACHE_LINE_SIZE, socket_id);\n-\n-\tif (lpm->rules_tbl == NULL) {\n-\t\tRTE_LOG(ERR, LPM, \"LPM rules_tbl allocation failed\\n\");\n-\t\trte_free(lpm);\n-\t\tlpm = NULL;\n-\t\trte_free(te);\n-\t\trte_errno = ENOMEM;\n-\t\tgoto exit;\n+\t\tgoto fail;\n \t}\n \n \t/* Save user arguments. */\n \tlpm->max_rules = config->max_rules;\n \tlpm->number_tbl8s = config->number_tbl8s;\n \tsnprintf(lpm->name, sizeof(lpm->name), \"%s\", name);\n+\tlpm->rules_tbl = rules_tbl;\n \n \tte->data = (void *) lpm;\n \n \tTAILQ_INSERT_TAIL(lpm_list, te, next);\n+\trte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);\n+\treturn lpm;\n \n-exit:\n+fail:\n \trte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);\n \n-\treturn lpm;\n+fail_wo_unlock:\n+\trte_hash_free(rules_tbl);\n+\n+\treturn NULL;\n }\n \n /*\n@@ -259,50 +332,86 @@ rte_lpm6_free(struct rte_lpm6 *lpm)\n \n \trte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);\n \n-\trte_free(lpm->rules_tbl);\n+\trte_hash_free(lpm->rules_tbl);\n \trte_free(lpm);\n \trte_free(te);\n }\n \n+/* Find a rule */\n+static inline int\n+rule_find_with_key(struct rte_lpm6 *lpm,\n+\t\t  const struct rte_lpm6_rule_key *rule_key,\n+\t\t  uint32_t *next_hop)\n+{\n+\tuint64_t hash_val;\n+\tint ret;\n+\n+\t/* lookup for a rule */\n+\tret = rte_hash_lookup_data(lpm->rules_tbl, (const void *) rule_key,\n+\t\t(void **) &hash_val);\n+\tif (ret >= 0) {\n+\t\t*next_hop = (uint32_t) hash_val;\n+\t\treturn 1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/* Find a rule */\n+static int\n+rule_find(struct rte_lpm6 *lpm, uint8_t *ip, uint8_t depth,\n+\t\t  uint32_t *next_hop)\n+{\n+\tstruct rte_lpm6_rule_key rule_key;\n+\n+\t/* init a rule key */\n+\trule_key_init(&rule_key, ip, depth);\n+\n+\treturn rule_find_with_key(lpm, &rule_key, next_hop);\n+}\n+\n /*\n  * Checks if a rule already exists in the rules table and updates\n  * the nexthop if so. Otherwise it adds a new rule if enough space is available.\n+ *\n+ * Returns:\n+ *    0 - next hop of existed rule is updated\n+ *    1 - new rule successfuly added\n+ *   <0 - error\n  */\n-static inline int32_t\n-rule_add(struct rte_lpm6 *lpm, uint8_t *ip, uint32_t next_hop, uint8_t depth)\n+static inline int\n+rule_add(struct rte_lpm6 *lpm, uint8_t *ip, uint8_t depth, uint32_t next_hop)\n {\n-\tuint32_t rule_index;\n-\n-\t/* Scan through rule list to see if rule already exists. */\n-\tfor (rule_index = 0; rule_index < lpm->used_rules; rule_index++) {\n+\tint ret, rule_exist;\n+\tstruct rte_lpm6_rule_key rule_key;\n+\tuint32_t unused;\n \n-\t\t/* If rule already exists update its next_hop and return. */\n-\t\tif ((memcmp (lpm->rules_tbl[rule_index].ip, ip,\n-\t\t\t\tRTE_LPM6_IPV6_ADDR_SIZE) == 0) &&\n-\t\t\t\tlpm->rules_tbl[rule_index].depth == depth) {\n-\t\t\tlpm->rules_tbl[rule_index].next_hop = next_hop;\n+\t/* init a rule key */\n+\trule_key_init(&rule_key, ip, depth);\n \n-\t\t\treturn rule_index;\n-\t\t}\n-\t}\n+\t/* Scan through rule list to see if rule already exists. */\n+\trule_exist = rule_find_with_key(lpm, &rule_key, &unused);\n \n \t/*\n \t * If rule does not exist check if there is space to add a new rule to\n \t * this rule group. If there is no space return error.\n \t */\n-\tif (lpm->used_rules == lpm->max_rules) {\n+\tif (!rule_exist && lpm->used_rules == lpm->max_rules)\n \t\treturn -ENOSPC;\n-\t}\n \n-\t/* If there is space for the new rule add it. */\n-\trte_memcpy(lpm->rules_tbl[rule_index].ip, ip, RTE_LPM6_IPV6_ADDR_SIZE);\n-\tlpm->rules_tbl[rule_index].next_hop = next_hop;\n-\tlpm->rules_tbl[rule_index].depth = depth;\n+\t/* add the rule or update rules next hop */\n+\tret = rte_hash_add_key_data(lpm->rules_tbl, &rule_key,\n+\t\t(void *)(uintptr_t) next_hop);\n+\tif (ret < 0)\n+\t\treturn ret;\n \n \t/* Increment the used rules counter for this rule group. */\n-\tlpm->used_rules++;\n+\tif (!rule_exist) {\n+\t\tlpm->used_rules++;\n+\t\treturn 1;\n+\t}\n \n-\treturn rule_index;\n+\treturn 0;\n }\n \n /*\n@@ -492,7 +601,7 @@ rte_lpm6_add_v1705(struct rte_lpm6 *lpm, uint8_t *ip, uint8_t depth,\n {\n \tstruct rte_lpm6_tbl_entry *tbl;\n \tstruct rte_lpm6_tbl_entry *tbl_next = NULL;\n-\tint32_t rule_index;\n+\tint32_t ret;\n \tint status;\n \tuint8_t masked_ip[RTE_LPM6_IPV6_ADDR_SIZE];\n \tint i;\n@@ -502,16 +611,14 @@ rte_lpm6_add_v1705(struct rte_lpm6 *lpm, uint8_t *ip, uint8_t depth,\n \t\treturn -EINVAL;\n \n \t/* Copy the IP and mask it to avoid modifying user's input data. */\n-\tmemcpy(masked_ip, ip, RTE_LPM6_IPV6_ADDR_SIZE);\n-\tmask_ip(masked_ip, depth);\n+\tip6_copy_addr(masked_ip, ip);\n+\tip6_mask_addr(masked_ip, depth);\n \n \t/* Add the rule to the rule table. */\n-\trule_index = rule_add(lpm, masked_ip, next_hop, depth);\n-\n+\tret = rule_add(lpm, masked_ip, depth, next_hop);\n \t/* If there is no space available for new rule return error. */\n-\tif (rule_index < 0) {\n-\t\treturn rule_index;\n-\t}\n+\tif (ret < 0)\n+\t\treturn ret;\n \n \t/* Inspect the first three bytes through tbl24 on the first step. */\n \ttbl = lpm->tbl24;\n@@ -724,30 +831,6 @@ MAP_STATIC_SYMBOL(int rte_lpm6_lookup_bulk_func(const struct rte_lpm6 *lpm,\n \t\t\t\tint32_t *next_hops, unsigned int n),\n \t\trte_lpm6_lookup_bulk_func_v1705);\n \n-/*\n- * Finds a rule in rule table.\n- * NOTE: Valid range for depth parameter is 1 .. 128 inclusive.\n- */\n-static inline int32_t\n-rule_find(struct rte_lpm6 *lpm, uint8_t *ip, uint8_t depth)\n-{\n-\tuint32_t rule_index;\n-\n-\t/* Scan used rules at given depth to find rule. */\n-\tfor (rule_index = 0; rule_index < lpm->used_rules; rule_index++) {\n-\t\t/* If rule is found return the rule index. */\n-\t\tif ((memcmp (lpm->rules_tbl[rule_index].ip, ip,\n-\t\t\t\tRTE_LPM6_IPV6_ADDR_SIZE) == 0) &&\n-\t\t\t\tlpm->rules_tbl[rule_index].depth == depth) {\n-\n-\t\t\treturn rule_index;\n-\t\t}\n-\t}\n-\n-\t/* If rule is not found return -ENOENT. */\n-\treturn -ENOENT;\n-}\n-\n /*\n  * Look for a rule in the high-level rules table\n  */\n@@ -775,8 +858,7 @@ int\n rte_lpm6_is_rule_present_v1705(struct rte_lpm6 *lpm, uint8_t *ip, uint8_t depth,\n \t\tuint32_t *next_hop)\n {\n-\tuint8_t ip_masked[RTE_LPM6_IPV6_ADDR_SIZE];\n-\tint32_t rule_index;\n+\tuint8_t masked_ip[RTE_LPM6_IPV6_ADDR_SIZE];\n \n \t/* Check user arguments. */\n \tif ((lpm == NULL) || next_hop == NULL || ip == NULL ||\n@@ -784,19 +866,10 @@ rte_lpm6_is_rule_present_v1705(struct rte_lpm6 *lpm, uint8_t *ip, uint8_t depth,\n \t\treturn -EINVAL;\n \n \t/* Copy the IP and mask it to avoid modifying user's input data. */\n-\tmemcpy(ip_masked, ip, RTE_LPM6_IPV6_ADDR_SIZE);\n-\tmask_ip(ip_masked, depth);\n-\n-\t/* Look for the rule using rule_find. */\n-\trule_index = rule_find(lpm, ip_masked, depth);\n-\n-\tif (rule_index >= 0) {\n-\t\t*next_hop = lpm->rules_tbl[rule_index].next_hop;\n-\t\treturn 1;\n-\t}\n+\tip6_copy_addr(masked_ip, ip);\n+\tip6_mask_addr(masked_ip, depth);\n \n-\t/* If rule is not found return 0. */\n-\treturn 0;\n+\treturn rule_find(lpm, masked_ip, depth, next_hop);\n }\n BIND_DEFAULT_SYMBOL(rte_lpm6_is_rule_present, _v1705, 17.05);\n MAP_STATIC_SYMBOL(int rte_lpm6_is_rule_present(struct rte_lpm6 *lpm,\n@@ -806,16 +879,25 @@ MAP_STATIC_SYMBOL(int rte_lpm6_is_rule_present(struct rte_lpm6 *lpm,\n /*\n  * Delete a rule from the rule table.\n  * NOTE: Valid range for depth parameter is 1 .. 128 inclusive.\n+ * return\n+ *\t  0 on success\n+ *   <0 on failure\n  */\n-static inline void\n-rule_delete(struct rte_lpm6 *lpm, int32_t rule_index)\n+static inline int\n+rule_delete(struct rte_lpm6 *lpm, uint8_t *ip, uint8_t depth)\n {\n-\t/*\n-\t * Overwrite redundant rule with last rule in group and decrement rule\n-\t * counter.\n-\t */\n-\tlpm->rules_tbl[rule_index] = lpm->rules_tbl[lpm->used_rules-1];\n-\tlpm->used_rules--;\n+\tint ret;\n+\tstruct rte_lpm6_rule_key rule_key;\n+\n+\t/* init rule key */\n+\trule_key_init(&rule_key, ip, depth);\n+\n+\t/* delete the rule */\n+\tret = rte_hash_del_key(lpm->rules_tbl, (void *) &rule_key);\n+\tif (ret >= 0)\n+\t\tlpm->used_rules--;\n+\n+\treturn ret;\n }\n \n /*\n@@ -824,9 +906,8 @@ rule_delete(struct rte_lpm6 *lpm, int32_t rule_index)\n int\n rte_lpm6_delete(struct rte_lpm6 *lpm, uint8_t *ip, uint8_t depth)\n {\n-\tint32_t rule_to_delete_index;\n-\tuint8_t ip_masked[RTE_LPM6_IPV6_ADDR_SIZE];\n-\tunsigned i;\n+\tuint8_t masked_ip[RTE_LPM6_IPV6_ADDR_SIZE];\n+\tint ret;\n \n \t/*\n \t * Check input arguments.\n@@ -836,24 +917,13 @@ rte_lpm6_delete(struct rte_lpm6 *lpm, uint8_t *ip, uint8_t depth)\n \t}\n \n \t/* Copy the IP and mask it to avoid modifying user's input data. */\n-\tmemcpy(ip_masked, ip, RTE_LPM6_IPV6_ADDR_SIZE);\n-\tmask_ip(ip_masked, depth);\n-\n-\t/*\n-\t * Find the index of the input rule, that needs to be deleted, in the\n-\t * rule table.\n-\t */\n-\trule_to_delete_index = rule_find(lpm, ip_masked, depth);\n-\n-\t/*\n-\t * Check if rule_to_delete_index was found. If no rule was found the\n-\t * function rule_find returns -ENOENT.\n-\t */\n-\tif (rule_to_delete_index < 0)\n-\t\treturn rule_to_delete_index;\n+\tip6_copy_addr(masked_ip, ip);\n+\tip6_mask_addr(masked_ip, depth);\n \n \t/* Delete the rule from the rule table. */\n-\trule_delete(lpm, rule_to_delete_index);\n+\tret = rule_delete(lpm, masked_ip, depth);\n+\tif (ret < 0)\n+\t\treturn -ENOENT;\n \n \t/*\n \t * Set all the table entries to 0 (ie delete every rule\n@@ -868,10 +938,7 @@ rte_lpm6_delete(struct rte_lpm6 *lpm, uint8_t *ip, uint8_t depth)\n \t * Add every rule again (except for the one that was removed from\n \t * the rules table).\n \t */\n-\tfor (i = 0; i < lpm->used_rules; i++) {\n-\t\trte_lpm6_add(lpm, lpm->rules_tbl[i].ip, lpm->rules_tbl[i].depth,\n-\t\t\t\tlpm->rules_tbl[i].next_hop);\n-\t}\n+\trebuild_lpm(lpm);\n \n \treturn 0;\n }\n@@ -883,37 +950,19 @@ int\n rte_lpm6_delete_bulk_func(struct rte_lpm6 *lpm,\n \t\tuint8_t ips[][RTE_LPM6_IPV6_ADDR_SIZE], uint8_t *depths, unsigned n)\n {\n-\tint32_t rule_to_delete_index;\n-\tuint8_t ip_masked[RTE_LPM6_IPV6_ADDR_SIZE];\n+\tuint8_t masked_ip[RTE_LPM6_IPV6_ADDR_SIZE];\n \tunsigned i;\n \n \t/*\n \t * Check input arguments.\n \t */\n-\tif ((lpm == NULL) || (ips == NULL) || (depths == NULL)) {\n+\tif ((lpm == NULL) || (ips == NULL) || (depths == NULL))\n \t\treturn -EINVAL;\n-\t}\n \n \tfor (i = 0; i < n; i++) {\n-\t\t/* Copy the IP and mask it to avoid modifying user's input data. */\n-\t\tmemcpy(ip_masked, ips[i], RTE_LPM6_IPV6_ADDR_SIZE);\n-\t\tmask_ip(ip_masked, depths[i]);\n-\n-\t\t/*\n-\t\t * Find the index of the input rule, that needs to be deleted, in the\n-\t\t * rule table.\n-\t\t */\n-\t\trule_to_delete_index = rule_find(lpm, ip_masked, depths[i]);\n-\n-\t\t/*\n-\t\t * Check if rule_to_delete_index was found. If no rule was found the\n-\t\t * function rule_find returns -ENOENT.\n-\t\t */\n-\t\tif (rule_to_delete_index < 0)\n-\t\t\tcontinue;\n-\n-\t\t/* Delete the rule from the rule table. */\n-\t\trule_delete(lpm, rule_to_delete_index);\n+\t\tip6_copy_addr(masked_ip, ips[i]);\n+\t\tip6_mask_addr(masked_ip, depths[i]);\n+\t\trule_delete(lpm, masked_ip, depths[i]);\n \t}\n \n \t/*\n@@ -929,10 +978,7 @@ rte_lpm6_delete_bulk_func(struct rte_lpm6 *lpm,\n \t * Add every rule again (except for the ones that were removed from\n \t * the rules table).\n \t */\n-\tfor (i = 0; i < lpm->used_rules; i++) {\n-\t\trte_lpm6_add(lpm, lpm->rules_tbl[i].ip, lpm->rules_tbl[i].depth,\n-\t\t\t\tlpm->rules_tbl[i].next_hop);\n-\t}\n+\trebuild_lpm(lpm);\n \n \treturn 0;\n }\n@@ -957,5 +1003,5 @@ rte_lpm6_delete_all(struct rte_lpm6 *lpm)\n \t\t\tRTE_LPM6_TBL8_GROUP_NUM_ENTRIES * lpm->number_tbl8s);\n \n \t/* Delete all rules form the rules table. */\n-\tmemset(lpm->rules_tbl, 0, sizeof(struct rte_lpm6_rule) * lpm->max_rules);\n+\trte_hash_reset(lpm->rules_tbl);\n }\n",
    "prefixes": [
        "v7",
        "1/2"
    ]
}