net/dpaa2: support extra stats
[dpdk.git] / lib / librte_table / rte_table_hash_key8.c
index 606805d..5f0c656 100644 (file)
@@ -35,6 +35,7 @@
 
 #include <rte_common.h>
 #include <rte_mbuf.h>
+#include <rte_memory.h>
 #include <rte_malloc.h>
 #include <rte_log.h>
 
 
 #define RTE_TABLE_HASH_KEY_SIZE                                                8
 
+#ifdef RTE_TABLE_STATS_COLLECT
+
+#define RTE_TABLE_HASH_KEY8_STATS_PKTS_IN_ADD(table, val) \
+       table->stats.n_pkts_in += val
+#define RTE_TABLE_HASH_KEY8_STATS_PKTS_LOOKUP_MISS(table, val) \
+       table->stats.n_pkts_lookup_miss += val
+
+#else
+
+#define RTE_TABLE_HASH_KEY8_STATS_PKTS_IN_ADD(table, val)
+#define RTE_TABLE_HASH_KEY8_STATS_PKTS_LOOKUP_MISS(table, val)
+
+#endif
+
 struct rte_bucket_4_8 {
        /* Cache line 0 */
        uint64_t signature;
@@ -57,6 +72,8 @@ struct rte_bucket_4_8 {
 };
 
 struct rte_table_hash {
+       struct rte_table_stats stats;
+
        /* Input parameters */
        uint32_t n_buckets;
        uint32_t n_entries_per_bucket;
@@ -65,6 +82,7 @@ struct rte_table_hash {
        uint32_t bucket_size;
        uint32_t signature_offset;
        uint32_t key_offset;
+       uint64_t key_mask;
        rte_table_hash_op_hash f_hash;
        uint64_t seed;
 
@@ -85,18 +103,6 @@ check_params_create_lru(struct rte_table_hash_key8_lru_params *params) {
                return -EINVAL;
        }
 
-       /* signature offset */
-       if ((params->signature_offset & 0x3) != 0) {
-               RTE_LOG(ERR, TABLE, "%s: invalid signature_offset\n", __func__);
-               return -EINVAL;
-       }
-
-       /* key offset */
-       if ((params->key_offset & 0x7) != 0) {
-               RTE_LOG(ERR, TABLE, "%s: invalid key_offset\n", __func__);
-               return -EINVAL;
-       }
-
        /* f_hash */
        if (params->f_hash == NULL) {
                RTE_LOG(ERR, TABLE, "%s: f_hash function pointer is NULL\n",
@@ -118,8 +124,8 @@ rte_table_hash_create_key8_lru(void *params, int socket_id, uint32_t entry_size)
 
        /* Check input parameters */
        if ((check_params_create_lru(p) != 0) ||
-               ((sizeof(struct rte_table_hash) % CACHE_LINE_SIZE) != 0) ||
-               ((sizeof(struct rte_bucket_4_8) % CACHE_LINE_SIZE) != 0)) {
+               ((sizeof(struct rte_table_hash) % RTE_CACHE_LINE_SIZE) != 0) ||
+               ((sizeof(struct rte_bucket_4_8) % 64) != 0)) {
                return NULL;
        }
        n_entries_per_bucket = 4;
@@ -129,11 +135,11 @@ rte_table_hash_create_key8_lru(void *params, int socket_id, uint32_t entry_size)
        n_buckets = rte_align32pow2((p->n_entries + n_entries_per_bucket - 1) /
                n_entries_per_bucket);
        bucket_size_cl = (sizeof(struct rte_bucket_4_8) + n_entries_per_bucket *
-               entry_size + CACHE_LINE_SIZE - 1) / CACHE_LINE_SIZE;
+               entry_size + RTE_CACHE_LINE_SIZE - 1) / RTE_CACHE_LINE_SIZE;
        total_size = sizeof(struct rte_table_hash) + n_buckets *
-               bucket_size_cl * CACHE_LINE_SIZE;
+               bucket_size_cl * RTE_CACHE_LINE_SIZE;
 
-       f = rte_zmalloc_socket("TABLE", total_size, CACHE_LINE_SIZE, socket_id);
+       f = rte_zmalloc_socket("TABLE", total_size, RTE_CACHE_LINE_SIZE, socket_id);
        if (f == NULL) {
                RTE_LOG(ERR, TABLE,
                        "%s: Cannot allocate %u bytes for hash table\n",
@@ -149,12 +155,17 @@ rte_table_hash_create_key8_lru(void *params, int socket_id, uint32_t entry_size)
        f->n_entries_per_bucket = n_entries_per_bucket;
        f->key_size = key_size;
        f->entry_size = entry_size;
-       f->bucket_size = bucket_size_cl * CACHE_LINE_SIZE;
+       f->bucket_size = bucket_size_cl * RTE_CACHE_LINE_SIZE;
        f->signature_offset = p->signature_offset;
        f->key_offset = p->key_offset;
        f->f_hash = p->f_hash;
        f->seed = p->seed;
 
+       if (p->key_mask != NULL)
+               f->key_mask = ((uint64_t *)p->key_mask)[0];
+       else
+               f->key_mask = 0xFFFFFFFFFFFFFFFFLLU;
+
        for (i = 0; i < n_buckets; i++) {
                struct rte_bucket_4_8 *bucket;
 
@@ -169,7 +180,7 @@ rte_table_hash_create_key8_lru(void *params, int socket_id, uint32_t entry_size)
 static int
 rte_table_hash_free_key8_lru(void *table)
 {
-       struct rte_table_hash *f = (struct rte_table_hash *) table;
+       struct rte_table_hash *f = table;
 
        /* Check input parameters */
        if (f == NULL) {
@@ -189,7 +200,7 @@ rte_table_hash_entry_add_key8_lru(
        int *key_found,
        void **entry_ptr)
 {
-       struct rte_table_hash *f = (struct rte_table_hash *) table;
+       struct rte_table_hash *f = table;
        struct rte_bucket_4_8 *bucket;
        uint64_t signature, mask, pos;
        uint32_t bucket_index, i;
@@ -252,7 +263,7 @@ rte_table_hash_entry_delete_key8_lru(
        int *key_found,
        void *entry)
 {
-       struct rte_table_hash *f = (struct rte_table_hash *) table;
+       struct rte_table_hash *f = table;
        struct rte_bucket_4_8 *bucket;
        uint64_t signature, mask;
        uint32_t bucket_index, i;
@@ -299,18 +310,6 @@ check_params_create_ext(struct rte_table_hash_key8_ext_params *params) {
                return -EINVAL;
        }
 
-       /* signature offset */
-       if ((params->signature_offset & 0x3) != 0) {
-               RTE_LOG(ERR, TABLE, "%s: invalid signature_offset\n", __func__);
-               return -EINVAL;
-       }
-
-       /* key offset */
-       if ((params->key_offset & 0x7) != 0) {
-               RTE_LOG(ERR, TABLE, "%s: invalid key_offset\n", __func__);
-               return -EINVAL;
-       }
-
        /* f_hash */
        if (params->f_hash == NULL) {
                RTE_LOG(ERR, TABLE, "%s: f_hash function pointer is NULL\n",
@@ -332,8 +331,8 @@ rte_table_hash_create_key8_ext(void *params, int socket_id, uint32_t entry_size)
 
        /* Check input parameters */
        if ((check_params_create_ext(p) != 0) ||
-               ((sizeof(struct rte_table_hash) % CACHE_LINE_SIZE) != 0) ||
-               ((sizeof(struct rte_bucket_4_8) % CACHE_LINE_SIZE) != 0))
+               ((sizeof(struct rte_table_hash) % RTE_CACHE_LINE_SIZE) != 0) ||
+               ((sizeof(struct rte_bucket_4_8) % 64) != 0))
                return NULL;
 
        n_entries_per_bucket = 4;
@@ -345,14 +344,14 @@ rte_table_hash_create_key8_ext(void *params, int socket_id, uint32_t entry_size)
        n_buckets_ext = (p->n_entries_ext + n_entries_per_bucket - 1) /
                n_entries_per_bucket;
        bucket_size_cl = (sizeof(struct rte_bucket_4_8) + n_entries_per_bucket *
-               entry_size + CACHE_LINE_SIZE - 1) / CACHE_LINE_SIZE;
-       stack_size_cl = (n_buckets_ext * sizeof(uint32_t) + CACHE_LINE_SIZE - 1)
-               / CACHE_LINE_SIZE;
+               entry_size + RTE_CACHE_LINE_SIZE - 1) / RTE_CACHE_LINE_SIZE;
+       stack_size_cl = (n_buckets_ext * sizeof(uint32_t) + RTE_CACHE_LINE_SIZE - 1)
+               / RTE_CACHE_LINE_SIZE;
        total_size = sizeof(struct rte_table_hash) + ((n_buckets +
                n_buckets_ext) * bucket_size_cl + stack_size_cl) *
-               CACHE_LINE_SIZE;
+               RTE_CACHE_LINE_SIZE;
 
-       f = rte_zmalloc_socket("TABLE", total_size, CACHE_LINE_SIZE, socket_id);
+       f = rte_zmalloc_socket("TABLE", total_size, RTE_CACHE_LINE_SIZE, socket_id);
        if (f == NULL) {
                RTE_LOG(ERR, TABLE,
                        "%s: Cannot allocate %u bytes for hash table\n",
@@ -368,7 +367,7 @@ rte_table_hash_create_key8_ext(void *params, int socket_id, uint32_t entry_size)
        f->n_entries_per_bucket = n_entries_per_bucket;
        f->key_size = key_size;
        f->entry_size = entry_size;
-       f->bucket_size = bucket_size_cl * CACHE_LINE_SIZE;
+       f->bucket_size = bucket_size_cl * RTE_CACHE_LINE_SIZE;
        f->signature_offset = p->signature_offset;
        f->key_offset = p->key_offset;
        f->f_hash = p->f_hash;
@@ -379,6 +378,11 @@ rte_table_hash_create_key8_ext(void *params, int socket_id, uint32_t entry_size)
        f->stack = (uint32_t *)
                &f->memory[(n_buckets + n_buckets_ext) * f->bucket_size];
 
+       if (p->key_mask != NULL)
+               f->key_mask = ((uint64_t *)p->key_mask)[0];
+       else
+               f->key_mask = 0xFFFFFFFFFFFFFFFFLLU;
+
        for (i = 0; i < n_buckets_ext; i++)
                f->stack[i] = i;
 
@@ -388,7 +392,7 @@ rte_table_hash_create_key8_ext(void *params, int socket_id, uint32_t entry_size)
 static int
 rte_table_hash_free_key8_ext(void *table)
 {
-       struct rte_table_hash *f = (struct rte_table_hash *) table;
+       struct rte_table_hash *f = table;
 
        /* Check input parameters */
        if (f == NULL) {
@@ -408,7 +412,7 @@ rte_table_hash_entry_add_key8_ext(
        int *key_found,
        void **entry_ptr)
 {
-       struct rte_table_hash *f = (struct rte_table_hash *) table;
+       struct rte_table_hash *f = table;
        struct rte_bucket_4_8 *bucket0, *bucket, *bucket_prev;
        uint64_t signature;
        uint32_t bucket_index, i;
@@ -489,7 +493,7 @@ rte_table_hash_entry_delete_key8_ext(
        int *key_found,
        void *entry)
 {
-       struct rte_table_hash *f = (struct rte_table_hash *) table;
+       struct rte_table_hash *f = table;
        struct rte_bucket_4_8 *bucket0, *bucket, *bucket_prev;
        uint64_t signature;
        uint32_t bucket_index, i;
@@ -527,9 +531,8 @@ rte_table_hash_entry_delete_key8_ext(
 
                                        memset(bucket, 0,
                                                sizeof(struct rte_bucket_4_8));
-                                       bucket_index = (bucket -
-                                               ((struct rte_bucket_4_8 *)
-                                               f->memory)) - f->n_buckets;
+                                       bucket_index = (((uint8_t *)bucket -
+                                               (uint8_t *)f->memory)/f->bucket_size) - f->n_buckets;
                                        f->stack[f->stack_pos++] = bucket_index;
                                }
 
@@ -565,16 +568,17 @@ rte_table_hash_entry_delete_key8_ext(
                pos = 3;                                        \
 }
 
-#define lookup1_stage0(pkt0_index, mbuf0, pkts, pkts_mask)     \
+#define lookup1_stage0(pkt0_index, mbuf0, pkts, pkts_mask, f)  \
 {                                                              \
        uint64_t pkt_mask;                                      \
+       uint32_t key_offset = f->key_offset;\
                                                                \
        pkt0_index = __builtin_ctzll(pkts_mask);                \
        pkt_mask = 1LLU << pkt0_index;                          \
        pkts_mask &= ~pkt_mask;                                 \
                                                                \
        mbuf0 = pkts[pkt0_index];                               \
-       rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf0, 0));   \
+       rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf0, key_offset));  \
 }
 
 #define lookup1_stage1(mbuf1, bucket1, f)                      \
@@ -594,9 +598,12 @@ rte_table_hash_entry_delete_key8_ext(
        uint64_t *key;                                          \
        uint64_t signature;                                     \
        uint32_t bucket_index;                                  \
+       uint64_t hash_key_buffer;                               \
                                                                \
        key = RTE_MBUF_METADATA_UINT64_PTR(mbuf1, f->key_offset);\
-       signature = f->f_hash(key, RTE_TABLE_HASH_KEY_SIZE, f->seed);\
+       hash_key_buffer = *key & f->key_mask;                   \
+       signature = f->f_hash(&hash_key_buffer,                 \
+               RTE_TABLE_HASH_KEY_SIZE, f->seed);              \
        bucket_index = signature & (f->n_buckets - 1);          \
        bucket1 = (struct rte_bucket_4_8 *)                     \
                &f->memory[bucket_index * f->bucket_size];      \
@@ -610,10 +617,12 @@ rte_table_hash_entry_delete_key8_ext(
        uint64_t pkt_mask;                                      \
        uint64_t *key;                                          \
        uint32_t pos;                                           \
+       uint64_t hash_key_buffer;                               \
                                                                \
        key = RTE_MBUF_METADATA_UINT64_PTR(mbuf2, f->key_offset);\
+       hash_key_buffer = key[0] & f->key_mask;                 \
                                                                \
-       lookup_key8_cmp(key, bucket2, pos);                     \
+       lookup_key8_cmp((&hash_key_buffer), bucket2, pos);      \
                                                                \
        pkt_mask = ((bucket2->signature >> pos) & 1LLU) << pkt2_index;\
        pkts_mask_out |= pkt_mask;                              \
@@ -632,10 +641,12 @@ rte_table_hash_entry_delete_key8_ext(
        uint64_t pkt_mask, bucket_mask;                         \
        uint64_t *key;                                          \
        uint32_t pos;                                           \
+       uint64_t hash_key_buffer;                               \
                                                                \
        key = RTE_MBUF_METADATA_UINT64_PTR(mbuf2, f->key_offset);\
+       hash_key_buffer = *key & f->key_mask;                   \
                                                                \
-       lookup_key8_cmp(key, bucket2, pos);                     \
+       lookup_key8_cmp((&hash_key_buffer), bucket2, pos);      \
                                                                \
        pkt_mask = ((bucket2->signature >> pos) & 1LLU) << pkt2_index;\
        pkts_mask_out |= pkt_mask;                              \
@@ -659,11 +670,13 @@ rte_table_hash_entry_delete_key8_ext(
        uint64_t pkt_mask, bucket_mask;                         \
        uint64_t *key;                                          \
        uint32_t pos;                                           \
+       uint64_t hash_key_buffer;                               \
                                                                \
        bucket = buckets[pkt_index];                            \
        key = keys[pkt_index];                                  \
+       hash_key_buffer = (*key) & f->key_mask;                 \
                                                                \
-       lookup_key8_cmp(key, bucket, pos);                      \
+       lookup_key8_cmp((&hash_key_buffer), bucket, pos);       \
                                                                \
        pkt_mask = ((bucket->signature >> pos) & 1LLU) << pkt_index;\
        pkts_mask_out |= pkt_mask;                              \
@@ -681,36 +694,38 @@ rte_table_hash_entry_delete_key8_ext(
 }
 
 #define lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01,\
-       pkts, pkts_mask)                                        \
+       pkts, pkts_mask, f)                                     \
 {                                                              \
        uint64_t pkt00_mask, pkt01_mask;                        \
+       uint32_t key_offset = f->key_offset;            \
                                                                \
        pkt00_index = __builtin_ctzll(pkts_mask);               \
        pkt00_mask = 1LLU << pkt00_index;                       \
        pkts_mask &= ~pkt00_mask;                               \
                                                                \
        mbuf00 = pkts[pkt00_index];                             \
-       rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf00, 0));  \
+       rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf00, key_offset));\
                                                                \
        pkt01_index = __builtin_ctzll(pkts_mask);               \
        pkt01_mask = 1LLU << pkt01_index;                       \
        pkts_mask &= ~pkt01_mask;                               \
                                                                \
        mbuf01 = pkts[pkt01_index];                             \
-       rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf01, 0));  \
+       rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf01, key_offset));\
 }
 
 #define lookup2_stage0_with_odd_support(pkt00_index, pkt01_index,\
-       mbuf00, mbuf01, pkts, pkts_mask)                        \
+       mbuf00, mbuf01, pkts, pkts_mask, f)                     \
 {                                                              \
        uint64_t pkt00_mask, pkt01_mask;                        \
+       uint32_t key_offset = f->key_offset;            \
                                                                \
        pkt00_index = __builtin_ctzll(pkts_mask);               \
        pkt00_mask = 1LLU << pkt00_index;                       \
        pkts_mask &= ~pkt00_mask;                               \
                                                                \
        mbuf00 = pkts[pkt00_index];                             \
-       rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf00, 0));  \
+       rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf00, key_offset));\
                                                                \
        pkt01_index = __builtin_ctzll(pkts_mask);               \
        if (pkts_mask == 0)                                     \
@@ -720,7 +735,7 @@ rte_table_hash_entry_delete_key8_ext(
        pkts_mask &= ~pkt01_mask;                               \
                                                                \
        mbuf01 = pkts[pkt01_index];                             \
-       rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf01, 0));  \
+       rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf01, key_offset));\
 }
 
 #define lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f)  \
@@ -744,6 +759,8 @@ rte_table_hash_entry_delete_key8_ext(
 #define lookup2_stage1_dosig(mbuf10, mbuf11, bucket10, bucket11, f)\
 {                                                              \
        uint64_t *key10, *key11;                                \
+       uint64_t hash_offset_buffer10;                          \
+       uint64_t hash_offset_buffer11;                          \
        uint64_t signature10, signature11;                      \
        uint32_t bucket10_index, bucket11_index;                \
        rte_table_hash_op_hash f_hash = f->f_hash;              \
@@ -752,14 +769,18 @@ rte_table_hash_entry_delete_key8_ext(
                                                                \
        key10 = RTE_MBUF_METADATA_UINT64_PTR(mbuf10, key_offset);\
        key11 = RTE_MBUF_METADATA_UINT64_PTR(mbuf11, key_offset);\
+       hash_offset_buffer10 = *key10 & f->key_mask;            \
+       hash_offset_buffer11 = *key11 & f->key_mask;            \
                                                                \
-       signature10 = f_hash(key10, RTE_TABLE_HASH_KEY_SIZE, seed);\
+       signature10 = f_hash(&hash_offset_buffer10,             \
+               RTE_TABLE_HASH_KEY_SIZE, seed);                 \
        bucket10_index = signature10 & (f->n_buckets - 1);      \
        bucket10 = (struct rte_bucket_4_8 *)                    \
                &f->memory[bucket10_index * f->bucket_size];    \
        rte_prefetch0(bucket10);                                \
                                                                \
-       signature11 = f_hash(key11, RTE_TABLE_HASH_KEY_SIZE, seed);\
+       signature11 = f_hash(&hash_offset_buffer11,             \
+               RTE_TABLE_HASH_KEY_SIZE, seed);                 \
        bucket11_index = signature11 & (f->n_buckets - 1);      \
        bucket11 = (struct rte_bucket_4_8 *)                    \
                &f->memory[bucket11_index * f->bucket_size];    \
@@ -772,13 +793,17 @@ rte_table_hash_entry_delete_key8_ext(
        void *a20, *a21;                                        \
        uint64_t pkt20_mask, pkt21_mask;                        \
        uint64_t *key20, *key21;                                \
+       uint64_t hash_offset_buffer20;                          \
+       uint64_t hash_offset_buffer21;                          \
        uint32_t pos20, pos21;                                  \
                                                                \
        key20 = RTE_MBUF_METADATA_UINT64_PTR(mbuf20, f->key_offset);\
        key21 = RTE_MBUF_METADATA_UINT64_PTR(mbuf21, f->key_offset);\
+       hash_offset_buffer20 = *key20 & f->key_mask;            \
+       hash_offset_buffer21 = *key21 & f->key_mask;            \
                                                                \
-       lookup_key8_cmp(key20, bucket20, pos20);                \
-       lookup_key8_cmp(key21, bucket21, pos21);                \
+       lookup_key8_cmp((&hash_offset_buffer20), bucket20, pos20);\
+       lookup_key8_cmp((&hash_offset_buffer21), bucket21, pos21);\
                                                                \
        pkt20_mask = ((bucket20->signature >> pos20) & 1LLU) << pkt20_index;\
        pkt21_mask = ((bucket21->signature >> pos21) & 1LLU) << pkt21_index;\
@@ -801,13 +826,17 @@ rte_table_hash_entry_delete_key8_ext(
        void *a20, *a21;                                        \
        uint64_t pkt20_mask, pkt21_mask, bucket20_mask, bucket21_mask;\
        uint64_t *key20, *key21;                                \
+       uint64_t hash_offset_buffer20;                          \
+       uint64_t hash_offset_buffer21;                          \
        uint32_t pos20, pos21;                                  \
                                                                \
        key20 = RTE_MBUF_METADATA_UINT64_PTR(mbuf20, f->key_offset);\
        key21 = RTE_MBUF_METADATA_UINT64_PTR(mbuf21, f->key_offset);\
+       hash_offset_buffer20 = *key20 & f->key_mask;            \
+       hash_offset_buffer21 = *key21 & f->key_mask;            \
                                                                \
-       lookup_key8_cmp(key20, bucket20, pos20);                \
-       lookup_key8_cmp(key21, bucket21, pos21);                \
+       lookup_key8_cmp((&hash_offset_buffer20), bucket20, pos20);\
+       lookup_key8_cmp((&hash_offset_buffer21), bucket21, pos21);\
                                                                \
        pkt20_mask = ((bucket20->signature >> pos20) & 1LLU) << pkt20_index;\
        pkt21_mask = ((bucket21->signature >> pos21) & 1LLU) << pkt21_index;\
@@ -846,6 +875,9 @@ rte_table_hash_lookup_key8_lru(
                        pkt11_index, pkt20_index, pkt21_index;
        uint64_t pkts_mask_out = 0;
 
+       __rte_unused uint32_t n_pkts_in = __builtin_popcountll(pkts_mask);
+       RTE_TABLE_HASH_KEY8_STATS_PKTS_IN_ADD(f, n_pkts_in);
+
        /* Cannot run the pipeline with less than 5 packets */
        if (__builtin_popcountll(pkts_mask) < 5) {
                for ( ; pkts_mask; ) {
@@ -853,13 +885,14 @@ rte_table_hash_lookup_key8_lru(
                        struct rte_mbuf *mbuf;
                        uint32_t pkt_index;
 
-                       lookup1_stage0(pkt_index, mbuf, pkts, pkts_mask);
+                       lookup1_stage0(pkt_index, mbuf, pkts, pkts_mask, f);
                        lookup1_stage1(mbuf, bucket, f);
                        lookup1_stage2_lru(pkt_index, mbuf, bucket,
                                        pkts_mask_out, entries, f);
                }
 
                *lookup_hit_mask = pkts_mask_out;
+               RTE_TABLE_HASH_KEY8_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in - __builtin_popcountll(pkts_mask_out));
                return 0;
        }
 
@@ -869,7 +902,7 @@ rte_table_hash_lookup_key8_lru(
         */
        /* Pipeline stage 0 */
        lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
-               pkts_mask);
+               pkts_mask, f);
 
        /* Pipeline feed */
        mbuf10 = mbuf00;
@@ -879,7 +912,7 @@ rte_table_hash_lookup_key8_lru(
 
        /* Pipeline stage 0 */
        lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
-               pkts_mask);
+               pkts_mask, f);
 
        /* Pipeline stage 1 */
        lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f);
@@ -903,7 +936,7 @@ rte_table_hash_lookup_key8_lru(
 
                /* Pipeline stage 0 */
                lookup2_stage0_with_odd_support(pkt00_index, pkt01_index,
-                       mbuf00, mbuf01, pkts, pkts_mask);
+                       mbuf00, mbuf01, pkts, pkts_mask, f);
 
                /* Pipeline stage 1 */
                lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f);
@@ -949,6 +982,7 @@ rte_table_hash_lookup_key8_lru(
                bucket20, bucket21, pkts_mask_out, entries, f);
 
        *lookup_hit_mask = pkts_mask_out;
+       RTE_TABLE_HASH_KEY8_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in - __builtin_popcountll(pkts_mask_out));
        return 0;
 } /* rte_table_hash_lookup_key8_lru() */
 
@@ -967,6 +1001,9 @@ rte_table_hash_lookup_key8_lru_dosig(
        uint32_t pkt11_index, pkt20_index, pkt21_index;
        uint64_t pkts_mask_out = 0;
 
+       __rte_unused uint32_t n_pkts_in = __builtin_popcountll(pkts_mask);
+       RTE_TABLE_HASH_KEY8_STATS_PKTS_IN_ADD(f, n_pkts_in);
+
        /* Cannot run the pipeline with less than 5 packets */
        if (__builtin_popcountll(pkts_mask) < 5) {
                for ( ; pkts_mask; ) {
@@ -974,13 +1011,14 @@ rte_table_hash_lookup_key8_lru_dosig(
                        struct rte_mbuf *mbuf;
                        uint32_t pkt_index;
 
-                       lookup1_stage0(pkt_index, mbuf, pkts, pkts_mask);
+                       lookup1_stage0(pkt_index, mbuf, pkts, pkts_mask, f);
                        lookup1_stage1_dosig(mbuf, bucket, f);
                        lookup1_stage2_lru(pkt_index, mbuf, bucket,
                                pkts_mask_out, entries, f);
                }
 
                *lookup_hit_mask = pkts_mask_out;
+               RTE_TABLE_HASH_KEY8_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in - __builtin_popcountll(pkts_mask_out));
                return 0;
        }
 
@@ -990,7 +1028,7 @@ rte_table_hash_lookup_key8_lru_dosig(
         */
        /* Pipeline stage 0 */
        lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
-               pkts_mask);
+               pkts_mask, f);
 
        /* Pipeline feed */
        mbuf10 = mbuf00;
@@ -1000,7 +1038,7 @@ rte_table_hash_lookup_key8_lru_dosig(
 
        /* Pipeline stage 0 */
        lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
-               pkts_mask);
+               pkts_mask, f);
 
        /* Pipeline stage 1 */
        lookup2_stage1_dosig(mbuf10, mbuf11, bucket10, bucket11, f);
@@ -1024,7 +1062,7 @@ rte_table_hash_lookup_key8_lru_dosig(
 
                /* Pipeline stage 0 */
                lookup2_stage0_with_odd_support(pkt00_index, pkt01_index,
-                       mbuf00, mbuf01, pkts, pkts_mask);
+                       mbuf00, mbuf01, pkts, pkts_mask, f);
 
                /* Pipeline stage 1 */
                lookup2_stage1_dosig(mbuf10, mbuf11, bucket10, bucket11, f);
@@ -1070,6 +1108,7 @@ rte_table_hash_lookup_key8_lru_dosig(
                bucket20, bucket21, pkts_mask_out, entries, f);
 
        *lookup_hit_mask = pkts_mask_out;
+       RTE_TABLE_HASH_KEY8_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in - __builtin_popcountll(pkts_mask_out));
        return 0;
 } /* rte_table_hash_lookup_key8_lru_dosig() */
 
@@ -1090,6 +1129,9 @@ rte_table_hash_lookup_key8_ext(
        struct rte_bucket_4_8 *buckets[RTE_PORT_IN_BURST_SIZE_MAX];
        uint64_t *keys[RTE_PORT_IN_BURST_SIZE_MAX];
 
+       __rte_unused uint32_t n_pkts_in = __builtin_popcountll(pkts_mask);
+       RTE_TABLE_HASH_KEY8_STATS_PKTS_IN_ADD(f, n_pkts_in);
+
        /* Cannot run the pipeline with less than 5 packets */
        if (__builtin_popcountll(pkts_mask) < 5) {
                for ( ; pkts_mask; ) {
@@ -1097,7 +1139,7 @@ rte_table_hash_lookup_key8_ext(
                        struct rte_mbuf *mbuf;
                        uint32_t pkt_index;
 
-                       lookup1_stage0(pkt_index, mbuf, pkts, pkts_mask);
+                       lookup1_stage0(pkt_index, mbuf, pkts, pkts_mask, f);
                        lookup1_stage1(mbuf, bucket, f);
                        lookup1_stage2_ext(pkt_index, mbuf, bucket,
                                pkts_mask_out, entries, buckets_mask, buckets,
@@ -1113,7 +1155,7 @@ rte_table_hash_lookup_key8_ext(
         */
        /* Pipeline stage 0 */
        lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
-               pkts_mask);
+               pkts_mask, f);
 
        /* Pipeline feed */
        mbuf10 = mbuf00;
@@ -1123,7 +1165,7 @@ rte_table_hash_lookup_key8_ext(
 
        /* Pipeline stage 0 */
        lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
-               pkts_mask);
+               pkts_mask, f);
 
        /* Pipeline stage 1 */
        lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f);
@@ -1147,7 +1189,7 @@ rte_table_hash_lookup_key8_ext(
 
                /* Pipeline stage 0 */
                lookup2_stage0_with_odd_support(pkt00_index, pkt01_index,
-                       mbuf00, mbuf01, pkts, pkts_mask);
+                       mbuf00, mbuf01, pkts, pkts_mask, f);
 
                /* Pipeline stage 1 */
                lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f);
@@ -1216,6 +1258,7 @@ grind_next_buckets:
        }
 
        *lookup_hit_mask = pkts_mask_out;
+       RTE_TABLE_HASH_KEY8_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in - __builtin_popcountll(pkts_mask_out));
        return 0;
 } /* rte_table_hash_lookup_key8_ext() */
 
@@ -1236,6 +1279,9 @@ rte_table_hash_lookup_key8_ext_dosig(
        struct rte_bucket_4_8 *buckets[RTE_PORT_IN_BURST_SIZE_MAX];
        uint64_t *keys[RTE_PORT_IN_BURST_SIZE_MAX];
 
+       __rte_unused uint32_t n_pkts_in = __builtin_popcountll(pkts_mask);
+       RTE_TABLE_HASH_KEY8_STATS_PKTS_IN_ADD(f, n_pkts_in);
+
        /* Cannot run the pipeline with less than 5 packets */
        if (__builtin_popcountll(pkts_mask) < 5) {
                for ( ; pkts_mask; ) {
@@ -1243,7 +1289,7 @@ rte_table_hash_lookup_key8_ext_dosig(
                        struct rte_mbuf *mbuf;
                        uint32_t pkt_index;
 
-                       lookup1_stage0(pkt_index, mbuf, pkts, pkts_mask);
+                       lookup1_stage0(pkt_index, mbuf, pkts, pkts_mask, f);
                        lookup1_stage1_dosig(mbuf, bucket, f);
                        lookup1_stage2_ext(pkt_index, mbuf, bucket,
                                pkts_mask_out, entries, buckets_mask,
@@ -1259,7 +1305,7 @@ rte_table_hash_lookup_key8_ext_dosig(
         */
        /* Pipeline stage 0 */
        lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
-               pkts_mask);
+               pkts_mask, f);
 
        /* Pipeline feed */
        mbuf10 = mbuf00;
@@ -1269,7 +1315,7 @@ rte_table_hash_lookup_key8_ext_dosig(
 
        /* Pipeline stage 0 */
        lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
-               pkts_mask);
+               pkts_mask, f);
 
        /* Pipeline stage 1 */
        lookup2_stage1_dosig(mbuf10, mbuf11, bucket10, bucket11, f);
@@ -1293,7 +1339,7 @@ rte_table_hash_lookup_key8_ext_dosig(
 
                /* Pipeline stage 0 */
                lookup2_stage0_with_odd_support(pkt00_index, pkt01_index,
-                       mbuf00, mbuf01, pkts, pkts_mask);
+                       mbuf00, mbuf01, pkts, pkts_mask, f);
 
                /* Pipeline stage 1 */
                lookup2_stage1_dosig(mbuf10, mbuf11, bucket10, bucket11, f);
@@ -1362,15 +1408,33 @@ grind_next_buckets:
        }
 
        *lookup_hit_mask = pkts_mask_out;
+       RTE_TABLE_HASH_KEY8_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in - __builtin_popcountll(pkts_mask_out));
        return 0;
 } /* rte_table_hash_lookup_key8_dosig_ext() */
 
+static int
+rte_table_hash_key8_stats_read(void *table, struct rte_table_stats *stats, int clear)
+{
+       struct rte_table_hash *t = table;
+
+       if (stats != NULL)
+               memcpy(stats, &t->stats, sizeof(t->stats));
+
+       if (clear)
+               memset(&t->stats, 0, sizeof(t->stats));
+
+       return 0;
+}
+
 struct rte_table_ops rte_table_hash_key8_lru_ops = {
        .f_create = rte_table_hash_create_key8_lru,
        .f_free = rte_table_hash_free_key8_lru,
        .f_add = rte_table_hash_entry_add_key8_lru,
        .f_delete = rte_table_hash_entry_delete_key8_lru,
+       .f_add_bulk = NULL,
+       .f_delete_bulk = NULL,
        .f_lookup = rte_table_hash_lookup_key8_lru,
+       .f_stats = rte_table_hash_key8_stats_read,
 };
 
 struct rte_table_ops rte_table_hash_key8_lru_dosig_ops = {
@@ -1378,7 +1442,10 @@ struct rte_table_ops rte_table_hash_key8_lru_dosig_ops = {
        .f_free = rte_table_hash_free_key8_lru,
        .f_add = rte_table_hash_entry_add_key8_lru,
        .f_delete = rte_table_hash_entry_delete_key8_lru,
+       .f_add_bulk = NULL,
+       .f_delete_bulk = NULL,
        .f_lookup = rte_table_hash_lookup_key8_lru_dosig,
+       .f_stats = rte_table_hash_key8_stats_read,
 };
 
 struct rte_table_ops rte_table_hash_key8_ext_ops = {
@@ -1386,7 +1453,10 @@ struct rte_table_ops rte_table_hash_key8_ext_ops = {
        .f_free = rte_table_hash_free_key8_ext,
        .f_add = rte_table_hash_entry_add_key8_ext,
        .f_delete = rte_table_hash_entry_delete_key8_ext,
+       .f_add_bulk = NULL,
+       .f_delete_bulk = NULL,
        .f_lookup = rte_table_hash_lookup_key8_ext,
+       .f_stats = rte_table_hash_key8_stats_read,
 };
 
 struct rte_table_ops rte_table_hash_key8_ext_dosig_ops = {
@@ -1394,5 +1464,8 @@ struct rte_table_ops rte_table_hash_key8_ext_dosig_ops = {
        .f_free = rte_table_hash_free_key8_ext,
        .f_add = rte_table_hash_entry_add_key8_ext,
        .f_delete = rte_table_hash_entry_delete_key8_ext,
+       .f_add_bulk = NULL,
+       .f_delete_bulk = NULL,
        .f_lookup = rte_table_hash_lookup_key8_ext_dosig,
+       .f_stats = rte_table_hash_key8_stats_read,
 };