table: add key mask to 8 and 16-byte hash parameters
[dpdk.git] / lib / librte_table / rte_table_hash_key8.c
1 /*-
2  *       BSD LICENSE
3  *
4  *       Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *       All rights reserved.
6  *
7  *       Redistribution and use in source and binary forms, with or without
8  *       modification, are permitted provided that the following conditions
9  *       are met:
10  *
11  *      * Redistributions of source code must retain the above copyright
12  *               notice, this list of conditions and the following disclaimer.
13  *      * Redistributions in binary form must reproduce the above copyright
14  *               notice, this list of conditions and the following disclaimer in
15  *               the documentation and/or other materials provided with the
16  *               distribution.
17  *      * Neither the name of Intel Corporation nor the names of its
18  *               contributors may be used to endorse or promote products derived
19  *               from this software without specific prior written permission.
20  *
21  *       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *       "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *       LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *       A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *       OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *       SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *       LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *       DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *       THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *       (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *       OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 #include <string.h>
34 #include <stdio.h>
35
36 #include <rte_common.h>
37 #include <rte_mbuf.h>
38 #include <rte_memory.h>
39 #include <rte_malloc.h>
40 #include <rte_log.h>
41
42 #include "rte_table_hash.h"
43 #include "rte_lru.h"
44
45 #define RTE_TABLE_HASH_KEY_SIZE                                         8
46
47 #ifdef RTE_TABLE_STATS_COLLECT
48
49 #define RTE_TABLE_HASH_KEY8_STATS_PKTS_IN_ADD(table, val) \
50         table->stats.n_pkts_in += val
51 #define RTE_TABLE_HASH_KEY8_STATS_PKTS_LOOKUP_MISS(table, val) \
52         table->stats.n_pkts_lookup_miss += val
53
54 #else
55
56 #define RTE_TABLE_HASH_KEY8_STATS_PKTS_IN_ADD(table, val)
57 #define RTE_TABLE_HASH_KEY8_STATS_PKTS_LOOKUP_MISS(table, val)
58
59 #endif
60
61 struct rte_bucket_4_8 {
62         /* Cache line 0 */
63         uint64_t signature;
64         uint64_t lru_list;
65         struct rte_bucket_4_8 *next;
66         uint64_t next_valid;
67
68         uint64_t key[4];
69
70         /* Cache line 1 */
71         uint8_t data[0];
72 };
73
74 struct rte_table_hash {
75         struct rte_table_stats stats;
76
77         /* Input parameters */
78         uint32_t n_buckets;
79         uint32_t n_entries_per_bucket;
80         uint32_t key_size;
81         uint32_t entry_size;
82         uint32_t bucket_size;
83         uint32_t signature_offset;
84         uint32_t key_offset;
85         uint64_t key_mask;
86         rte_table_hash_op_hash f_hash;
87         uint64_t seed;
88
89         /* Extendible buckets */
90         uint32_t n_buckets_ext;
91         uint32_t stack_pos;
92         uint32_t *stack;
93
94         /* Lookup table */
95         uint8_t memory[0] __rte_cache_aligned;
96 };
97
98 static int
99 check_params_create_lru(struct rte_table_hash_key8_lru_params *params) {
100         /* n_entries */
101         if (params->n_entries == 0) {
102                 RTE_LOG(ERR, TABLE, "%s: n_entries is zero\n", __func__);
103                 return -EINVAL;
104         }
105
106         /* f_hash */
107         if (params->f_hash == NULL) {
108                 RTE_LOG(ERR, TABLE, "%s: f_hash function pointer is NULL\n",
109                         __func__);
110                 return -EINVAL;
111         }
112
113         return 0;
114 }
115
116 static void *
117 rte_table_hash_create_key8_lru(void *params, int socket_id, uint32_t entry_size)
118 {
119         struct rte_table_hash_key8_lru_params *p =
120                 (struct rte_table_hash_key8_lru_params *) params;
121         struct rte_table_hash *f;
122         uint32_t n_buckets, n_entries_per_bucket, key_size, bucket_size_cl;
123         uint32_t total_size, i;
124
125         /* Check input parameters */
126         if ((check_params_create_lru(p) != 0) ||
127                 ((sizeof(struct rte_table_hash) % RTE_CACHE_LINE_SIZE) != 0) ||
128                 ((sizeof(struct rte_bucket_4_8) % RTE_CACHE_LINE_SIZE) != 0)) {
129                 return NULL;
130         }
131         n_entries_per_bucket = 4;
132         key_size = 8;
133
134         /* Memory allocation */
135         n_buckets = rte_align32pow2((p->n_entries + n_entries_per_bucket - 1) /
136                 n_entries_per_bucket);
137         bucket_size_cl = (sizeof(struct rte_bucket_4_8) + n_entries_per_bucket *
138                 entry_size + RTE_CACHE_LINE_SIZE - 1) / RTE_CACHE_LINE_SIZE;
139         total_size = sizeof(struct rte_table_hash) + n_buckets *
140                 bucket_size_cl * RTE_CACHE_LINE_SIZE;
141
142         f = rte_zmalloc_socket("TABLE", total_size, RTE_CACHE_LINE_SIZE, socket_id);
143         if (f == NULL) {
144                 RTE_LOG(ERR, TABLE,
145                         "%s: Cannot allocate %u bytes for hash table\n",
146                         __func__, total_size);
147                 return NULL;
148         }
149         RTE_LOG(INFO, TABLE,
150                 "%s: Hash table memory footprint is %u bytes\n",
151                 __func__, total_size);
152
153         /* Memory initialization */
154         f->n_buckets = n_buckets;
155         f->n_entries_per_bucket = n_entries_per_bucket;
156         f->key_size = key_size;
157         f->entry_size = entry_size;
158         f->bucket_size = bucket_size_cl * RTE_CACHE_LINE_SIZE;
159         f->signature_offset = p->signature_offset;
160         f->key_offset = p->key_offset;
161         f->f_hash = p->f_hash;
162         f->seed = p->seed;
163
164         if (p->key_mask != NULL)
165                 f->key_mask = ((uint64_t *)p->key_mask)[0];
166         else
167                 f->key_mask = 0xFFFFFFFFFFFFFFFFLLU;
168
169         for (i = 0; i < n_buckets; i++) {
170                 struct rte_bucket_4_8 *bucket;
171
172                 bucket = (struct rte_bucket_4_8 *) &f->memory[i *
173                         f->bucket_size];
174                 bucket->lru_list = 0x0000000100020003LLU;
175         }
176
177         return f;
178 }
179
180 static int
181 rte_table_hash_free_key8_lru(void *table)
182 {
183         struct rte_table_hash *f = (struct rte_table_hash *) table;
184
185         /* Check input parameters */
186         if (f == NULL) {
187                 RTE_LOG(ERR, TABLE, "%s: table parameter is NULL\n", __func__);
188                 return -EINVAL;
189         }
190
191         rte_free(f);
192         return 0;
193 }
194
195 static int
196 rte_table_hash_entry_add_key8_lru(
197         void *table,
198         void *key,
199         void *entry,
200         int *key_found,
201         void **entry_ptr)
202 {
203         struct rte_table_hash *f = (struct rte_table_hash *) table;
204         struct rte_bucket_4_8 *bucket;
205         uint64_t signature, mask, pos;
206         uint32_t bucket_index, i;
207
208         signature = f->f_hash(key, f->key_size, f->seed);
209         bucket_index = signature & (f->n_buckets - 1);
210         bucket = (struct rte_bucket_4_8 *)
211                 &f->memory[bucket_index * f->bucket_size];
212
213         /* Key is present in the bucket */
214         for (i = 0, mask = 1LLU; i < 4; i++, mask <<= 1) {
215                 uint64_t bucket_signature = bucket->signature;
216                 uint64_t bucket_key = bucket->key[i];
217
218                 if ((bucket_signature & mask) &&
219                     (*((uint64_t *) key) == bucket_key)) {
220                         uint8_t *bucket_data = &bucket->data[i * f->entry_size];
221
222                         memcpy(bucket_data, entry, f->entry_size);
223                         lru_update(bucket, i);
224                         *key_found = 1;
225                         *entry_ptr = (void *) bucket_data;
226                         return 0;
227                 }
228         }
229
230         /* Key is not present in the bucket */
231         for (i = 0, mask = 1LLU; i < 4; i++, mask <<= 1) {
232                 uint64_t bucket_signature = bucket->signature;
233
234                 if ((bucket_signature & mask) == 0) {
235                         uint8_t *bucket_data = &bucket->data[i * f->entry_size];
236
237                         bucket->signature |= mask;
238                         bucket->key[i] = *((uint64_t *) key);
239                         memcpy(bucket_data, entry, f->entry_size);
240                         lru_update(bucket, i);
241                         *key_found = 0;
242                         *entry_ptr = (void *) bucket_data;
243
244                         return 0;
245                 }
246         }
247
248         /* Bucket full: replace LRU entry */
249         pos = lru_pos(bucket);
250         bucket->key[pos] = *((uint64_t *) key);
251         memcpy(&bucket->data[pos * f->entry_size], entry, f->entry_size);
252         lru_update(bucket, pos);
253         *key_found      = 0;
254         *entry_ptr = (void *) &bucket->data[pos * f->entry_size];
255
256         return 0;
257 }
258
259 static int
260 rte_table_hash_entry_delete_key8_lru(
261         void *table,
262         void *key,
263         int *key_found,
264         void *entry)
265 {
266         struct rte_table_hash *f = (struct rte_table_hash *) table;
267         struct rte_bucket_4_8 *bucket;
268         uint64_t signature, mask;
269         uint32_t bucket_index, i;
270
271         signature = f->f_hash(key, f->key_size, f->seed);
272         bucket_index = signature & (f->n_buckets - 1);
273         bucket = (struct rte_bucket_4_8 *)
274                 &f->memory[bucket_index * f->bucket_size];
275
276         /* Key is present in the bucket */
277         for (i = 0, mask = 1LLU; i < 4; i++, mask <<= 1) {
278                 uint64_t bucket_signature = bucket->signature;
279                 uint64_t bucket_key = bucket->key[i];
280
281                 if ((bucket_signature & mask) &&
282                     (*((uint64_t *) key) == bucket_key)) {
283                         uint8_t *bucket_data = &bucket->data[i * f->entry_size];
284
285                         bucket->signature &= ~mask;
286                         *key_found = 1;
287                         if (entry)
288                                 memcpy(entry, bucket_data, f->entry_size);
289
290                         return 0;
291                 }
292         }
293
294         /* Key is not present in the bucket */
295         *key_found = 0;
296         return 0;
297 }
298
299 static int
300 check_params_create_ext(struct rte_table_hash_key8_ext_params *params) {
301         /* n_entries */
302         if (params->n_entries == 0) {
303                 RTE_LOG(ERR, TABLE, "%s: n_entries is zero\n", __func__);
304                 return -EINVAL;
305         }
306
307         /* n_entries_ext */
308         if (params->n_entries_ext == 0) {
309                 RTE_LOG(ERR, TABLE, "%s: n_entries_ext is zero\n", __func__);
310                 return -EINVAL;
311         }
312
313         /* f_hash */
314         if (params->f_hash == NULL) {
315                 RTE_LOG(ERR, TABLE, "%s: f_hash function pointer is NULL\n",
316                         __func__);
317                 return -EINVAL;
318         }
319
320         return 0;
321 }
322
323 static void *
324 rte_table_hash_create_key8_ext(void *params, int socket_id, uint32_t entry_size)
325 {
326         struct rte_table_hash_key8_ext_params *p =
327                 (struct rte_table_hash_key8_ext_params *) params;
328         struct rte_table_hash *f;
329         uint32_t n_buckets, n_buckets_ext, n_entries_per_bucket, key_size;
330         uint32_t bucket_size_cl, stack_size_cl, total_size, i;
331
332         /* Check input parameters */
333         if ((check_params_create_ext(p) != 0) ||
334                 ((sizeof(struct rte_table_hash) % RTE_CACHE_LINE_SIZE) != 0) ||
335                 ((sizeof(struct rte_bucket_4_8) % RTE_CACHE_LINE_SIZE) != 0))
336                 return NULL;
337
338         n_entries_per_bucket = 4;
339         key_size = 8;
340
341         /* Memory allocation */
342         n_buckets = rte_align32pow2((p->n_entries + n_entries_per_bucket - 1) /
343                 n_entries_per_bucket);
344         n_buckets_ext = (p->n_entries_ext + n_entries_per_bucket - 1) /
345                 n_entries_per_bucket;
346         bucket_size_cl = (sizeof(struct rte_bucket_4_8) + n_entries_per_bucket *
347                 entry_size + RTE_CACHE_LINE_SIZE - 1) / RTE_CACHE_LINE_SIZE;
348         stack_size_cl = (n_buckets_ext * sizeof(uint32_t) + RTE_CACHE_LINE_SIZE - 1)
349                 / RTE_CACHE_LINE_SIZE;
350         total_size = sizeof(struct rte_table_hash) + ((n_buckets +
351                 n_buckets_ext) * bucket_size_cl + stack_size_cl) *
352                 RTE_CACHE_LINE_SIZE;
353
354         f = rte_zmalloc_socket("TABLE", total_size, RTE_CACHE_LINE_SIZE, socket_id);
355         if (f == NULL) {
356                 RTE_LOG(ERR, TABLE,
357                         "%s: Cannot allocate %u bytes for hash table\n",
358                         __func__, total_size);
359                 return NULL;
360         }
361         RTE_LOG(INFO, TABLE,
362                 "%s: Hash table memory footprint is %u bytes\n",
363                 __func__, total_size);
364
365         /* Memory initialization */
366         f->n_buckets = n_buckets;
367         f->n_entries_per_bucket = n_entries_per_bucket;
368         f->key_size = key_size;
369         f->entry_size = entry_size;
370         f->bucket_size = bucket_size_cl * RTE_CACHE_LINE_SIZE;
371         f->signature_offset = p->signature_offset;
372         f->key_offset = p->key_offset;
373         f->f_hash = p->f_hash;
374         f->seed = p->seed;
375
376         f->n_buckets_ext = n_buckets_ext;
377         f->stack_pos = n_buckets_ext;
378         f->stack = (uint32_t *)
379                 &f->memory[(n_buckets + n_buckets_ext) * f->bucket_size];
380
381         if (p->key_mask != NULL)
382                 f->key_mask = ((uint64_t *)p->key_mask)[0];
383         else
384                 f->key_mask = 0xFFFFFFFFFFFFFFFFLLU;
385
386         for (i = 0; i < n_buckets_ext; i++)
387                 f->stack[i] = i;
388
389         return f;
390 }
391
392 static int
393 rte_table_hash_free_key8_ext(void *table)
394 {
395         struct rte_table_hash *f = (struct rte_table_hash *) table;
396
397         /* Check input parameters */
398         if (f == NULL) {
399                 RTE_LOG(ERR, TABLE, "%s: table parameter is NULL\n", __func__);
400                 return -EINVAL;
401         }
402
403         rte_free(f);
404         return 0;
405 }
406
407 static int
408 rte_table_hash_entry_add_key8_ext(
409         void *table,
410         void *key,
411         void *entry,
412         int *key_found,
413         void **entry_ptr)
414 {
415         struct rte_table_hash *f = (struct rte_table_hash *) table;
416         struct rte_bucket_4_8 *bucket0, *bucket, *bucket_prev;
417         uint64_t signature;
418         uint32_t bucket_index, i;
419
420         signature = f->f_hash(key, f->key_size, f->seed);
421         bucket_index = signature & (f->n_buckets - 1);
422         bucket0 = (struct rte_bucket_4_8 *)
423                 &f->memory[bucket_index * f->bucket_size];
424
425         /* Key is present in the bucket */
426         for (bucket = bucket0; bucket != NULL; bucket = bucket->next) {
427                 uint64_t mask;
428
429                 for (i = 0, mask = 1LLU; i < 4; i++, mask <<= 1) {
430                         uint64_t bucket_signature = bucket->signature;
431                         uint64_t bucket_key = bucket->key[i];
432
433                         if ((bucket_signature & mask) &&
434                                         (*((uint64_t *) key) == bucket_key)) {
435                                 uint8_t *bucket_data = &bucket->data[i *
436                                         f->entry_size];
437
438                                 memcpy(bucket_data, entry, f->entry_size);
439                                 *key_found = 1;
440                                 *entry_ptr = (void *) bucket_data;
441                                 return 0;
442                         }
443                 }
444         }
445
446         /* Key is not present in the bucket */
447         for (bucket_prev = NULL, bucket = bucket0;
448                 bucket != NULL; bucket_prev = bucket, bucket = bucket->next) {
449                 uint64_t mask;
450
451                 for (i = 0, mask = 1LLU; i < 4; i++, mask <<= 1) {
452                         uint64_t bucket_signature = bucket->signature;
453
454                         if ((bucket_signature & mask) == 0) {
455                                 uint8_t *bucket_data = &bucket->data[i *
456                                         f->entry_size];
457
458                                 bucket->signature |= mask;
459                                 bucket->key[i] = *((uint64_t *) key);
460                                 memcpy(bucket_data, entry, f->entry_size);
461                                 *key_found = 0;
462                                 *entry_ptr = (void *) bucket_data;
463
464                                 return 0;
465                         }
466                 }
467         }
468
469         /* Bucket full: extend bucket */
470         if (f->stack_pos > 0) {
471                 bucket_index = f->stack[--f->stack_pos];
472
473                 bucket = (struct rte_bucket_4_8 *) &f->memory[(f->n_buckets +
474                         bucket_index) * f->bucket_size];
475                 bucket_prev->next = bucket;
476                 bucket_prev->next_valid = 1;
477
478                 bucket->signature = 1;
479                 bucket->key[0] = *((uint64_t *) key);
480                 memcpy(&bucket->data[0], entry, f->entry_size);
481                 *key_found = 0;
482                 *entry_ptr = (void *) &bucket->data[0];
483                 return 0;
484         }
485
486         return -ENOSPC;
487 }
488
489 static int
490 rte_table_hash_entry_delete_key8_ext(
491         void *table,
492         void *key,
493         int *key_found,
494         void *entry)
495 {
496         struct rte_table_hash *f = (struct rte_table_hash *) table;
497         struct rte_bucket_4_8 *bucket0, *bucket, *bucket_prev;
498         uint64_t signature;
499         uint32_t bucket_index, i;
500
501         signature = f->f_hash(key, f->key_size, f->seed);
502         bucket_index = signature & (f->n_buckets - 1);
503         bucket0 = (struct rte_bucket_4_8 *)
504                 &f->memory[bucket_index * f->bucket_size];
505
506         /* Key is present in the bucket */
507         for (bucket_prev = NULL, bucket = bucket0; bucket != NULL;
508                 bucket_prev = bucket, bucket = bucket->next) {
509                 uint64_t mask;
510
511                 for (i = 0, mask = 1LLU; i < 4; i++, mask <<= 1) {
512                         uint64_t bucket_signature = bucket->signature;
513                         uint64_t bucket_key = bucket->key[i];
514
515                         if ((bucket_signature & mask) &&
516                                 (*((uint64_t *) key) == bucket_key)) {
517                                 uint8_t *bucket_data = &bucket->data[i *
518                                         f->entry_size];
519
520                                 bucket->signature &= ~mask;
521                                 *key_found = 1;
522                                 if (entry)
523                                         memcpy(entry, bucket_data,
524                                                 f->entry_size);
525
526                                 if ((bucket->signature == 0) &&
527                                     (bucket_prev != NULL)) {
528                                         bucket_prev->next = bucket->next;
529                                         bucket_prev->next_valid =
530                                                 bucket->next_valid;
531
532                                         memset(bucket, 0,
533                                                 sizeof(struct rte_bucket_4_8));
534                                         bucket_index = (((uint8_t *)bucket -
535                                                 (uint8_t *)f->memory)/f->bucket_size) - f->n_buckets;
536                                         f->stack[f->stack_pos++] = bucket_index;
537                                 }
538
539                                 return 0;
540                         }
541                 }
542         }
543
544         /* Key is not present in the bucket */
545         *key_found = 0;
546         return 0;
547 }
548
549 #define lookup_key8_cmp(key_in, bucket, pos)                    \
550 {                                                               \
551         uint64_t xor[4], signature;                             \
552                                                                 \
553         signature = ~bucket->signature;                         \
554                                                                 \
555         xor[0] = (key_in[0] ^    bucket->key[0]) | (signature & 1);\
556         xor[1] = (key_in[0] ^    bucket->key[1]) | (signature & 2);\
557         xor[2] = (key_in[0] ^    bucket->key[2]) | (signature & 4);\
558         xor[3] = (key_in[0] ^    bucket->key[3]) | (signature & 8);\
559                                                                 \
560         pos = 4;                                                \
561         if (xor[0] == 0)                                        \
562                 pos = 0;                                        \
563         if (xor[1] == 0)                                        \
564                 pos = 1;                                        \
565         if (xor[2] == 0)                                        \
566                 pos = 2;                                        \
567         if (xor[3] == 0)                                        \
568                 pos = 3;                                        \
569 }
570
571 #define lookup1_stage0(pkt0_index, mbuf0, pkts, pkts_mask)      \
572 {                                                               \
573         uint64_t pkt_mask;                                      \
574                                                                 \
575         pkt0_index = __builtin_ctzll(pkts_mask);                \
576         pkt_mask = 1LLU << pkt0_index;                          \
577         pkts_mask &= ~pkt_mask;                                 \
578                                                                 \
579         mbuf0 = pkts[pkt0_index];                               \
580         rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf0, 0));   \
581 }
582
583 #define lookup1_stage1(mbuf1, bucket1, f)                       \
584 {                                                               \
585         uint64_t signature;                                     \
586         uint32_t bucket_index;                                  \
587                                                                 \
588         signature = RTE_MBUF_METADATA_UINT32(mbuf1, f->signature_offset);\
589         bucket_index = signature & (f->n_buckets - 1);          \
590         bucket1 = (struct rte_bucket_4_8 *)                     \
591                 &f->memory[bucket_index * f->bucket_size];      \
592         rte_prefetch0(bucket1);                                 \
593 }
594
595 #define lookup1_stage1_dosig(mbuf1, bucket1, f)                 \
596 {                                                               \
597         uint64_t *key;                                          \
598         uint64_t signature;                                     \
599         uint32_t bucket_index;                                  \
600         uint64_t hash_key_buffer;                               \
601                                                                 \
602         key = RTE_MBUF_METADATA_UINT64_PTR(mbuf1, f->key_offset);\
603         hash_key_buffer = *key & f->key_mask;                   \
604         signature = f->f_hash(&hash_key_buffer,                 \
605                 RTE_TABLE_HASH_KEY_SIZE, f->seed);              \
606         bucket_index = signature & (f->n_buckets - 1);          \
607         bucket1 = (struct rte_bucket_4_8 *)                     \
608                 &f->memory[bucket_index * f->bucket_size];      \
609         rte_prefetch0(bucket1);                                 \
610 }
611
612 #define lookup1_stage2_lru(pkt2_index, mbuf2, bucket2,          \
613         pkts_mask_out, entries, f)                              \
614 {                                                               \
615         void *a;                                                \
616         uint64_t pkt_mask;                                      \
617         uint64_t *key;                                          \
618         uint32_t pos;                                           \
619         uint64_t hash_key_buffer;                               \
620                                                                 \
621         key = RTE_MBUF_METADATA_UINT64_PTR(mbuf2, f->key_offset);\
622         hash_key_buffer = key[0] & f->key_mask;                 \
623                                                                 \
624         lookup_key8_cmp((&hash_key_buffer), bucket2, pos);      \
625                                                                 \
626         pkt_mask = ((bucket2->signature >> pos) & 1LLU) << pkt2_index;\
627         pkts_mask_out |= pkt_mask;                              \
628                                                                 \
629         a = (void *) &bucket2->data[pos * f->entry_size];       \
630         rte_prefetch0(a);                                       \
631         entries[pkt2_index] = a;                                \
632         lru_update(bucket2, pos);                               \
633 }
634
635 #define lookup1_stage2_ext(pkt2_index, mbuf2, bucket2, pkts_mask_out,\
636         entries, buckets_mask, buckets, keys, f)                \
637 {                                                               \
638         struct rte_bucket_4_8 *bucket_next;                     \
639         void *a;                                                \
640         uint64_t pkt_mask, bucket_mask;                         \
641         uint64_t *key;                                          \
642         uint32_t pos;                                           \
643         uint64_t hash_key_buffer;                               \
644                                                                 \
645         key = RTE_MBUF_METADATA_UINT64_PTR(mbuf2, f->key_offset);\
646         hash_key_buffer = *key & f->key_mask;                   \
647                                                                 \
648         lookup_key8_cmp((&hash_key_buffer), bucket2, pos);      \
649                                                                 \
650         pkt_mask = ((bucket2->signature >> pos) & 1LLU) << pkt2_index;\
651         pkts_mask_out |= pkt_mask;                              \
652                                                                 \
653         a = (void *) &bucket2->data[pos * f->entry_size];       \
654         rte_prefetch0(a);                                       \
655         entries[pkt2_index] = a;                                \
656                                                                 \
657         bucket_mask = (~pkt_mask) & (bucket2->next_valid << pkt2_index);\
658         buckets_mask |= bucket_mask;                            \
659         bucket_next = bucket2->next;                            \
660         buckets[pkt2_index] = bucket_next;                      \
661         keys[pkt2_index] = key;                                 \
662 }
663
664 #define lookup_grinder(pkt_index, buckets, keys, pkts_mask_out, entries,\
665         buckets_mask, f)                                        \
666 {                                                               \
667         struct rte_bucket_4_8 *bucket, *bucket_next;            \
668         void *a;                                                \
669         uint64_t pkt_mask, bucket_mask;                         \
670         uint64_t *key;                                          \
671         uint32_t pos;                                           \
672         uint64_t hash_key_buffer;                               \
673                                                                 \
674         bucket = buckets[pkt_index];                            \
675         key = keys[pkt_index];                                  \
676         hash_key_buffer = (*key) & f->key_mask;                 \
677                                                                 \
678         lookup_key8_cmp((&hash_key_buffer), bucket, pos);       \
679                                                                 \
680         pkt_mask = ((bucket->signature >> pos) & 1LLU) << pkt_index;\
681         pkts_mask_out |= pkt_mask;                              \
682                                                                 \
683         a = (void *) &bucket->data[pos * f->entry_size];        \
684         rte_prefetch0(a);                                       \
685         entries[pkt_index] = a;                                 \
686                                                                 \
687         bucket_mask = (~pkt_mask) & (bucket->next_valid << pkt_index);\
688         buckets_mask |= bucket_mask;                            \
689         bucket_next = bucket->next;                             \
690         rte_prefetch0(bucket_next);                             \
691         buckets[pkt_index] = bucket_next;                       \
692         keys[pkt_index] = key;                                  \
693 }
694
695 #define lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01,\
696         pkts, pkts_mask)                                        \
697 {                                                               \
698         uint64_t pkt00_mask, pkt01_mask;                        \
699                                                                 \
700         pkt00_index = __builtin_ctzll(pkts_mask);               \
701         pkt00_mask = 1LLU << pkt00_index;                       \
702         pkts_mask &= ~pkt00_mask;                               \
703                                                                 \
704         mbuf00 = pkts[pkt00_index];                             \
705         rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf00, 0));  \
706                                                                 \
707         pkt01_index = __builtin_ctzll(pkts_mask);               \
708         pkt01_mask = 1LLU << pkt01_index;                       \
709         pkts_mask &= ~pkt01_mask;                               \
710                                                                 \
711         mbuf01 = pkts[pkt01_index];                             \
712         rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf01, 0));  \
713 }
714
715 #define lookup2_stage0_with_odd_support(pkt00_index, pkt01_index,\
716         mbuf00, mbuf01, pkts, pkts_mask)                        \
717 {                                                               \
718         uint64_t pkt00_mask, pkt01_mask;                        \
719                                                                 \
720         pkt00_index = __builtin_ctzll(pkts_mask);               \
721         pkt00_mask = 1LLU << pkt00_index;                       \
722         pkts_mask &= ~pkt00_mask;                               \
723                                                                 \
724         mbuf00 = pkts[pkt00_index];                             \
725         rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf00, 0));  \
726                                                                 \
727         pkt01_index = __builtin_ctzll(pkts_mask);               \
728         if (pkts_mask == 0)                                     \
729                 pkt01_index = pkt00_index;                      \
730                                                                 \
731         pkt01_mask = 1LLU << pkt01_index;                       \
732         pkts_mask &= ~pkt01_mask;                               \
733                                                                 \
734         mbuf01 = pkts[pkt01_index];                             \
735         rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf01, 0));  \
736 }
737
738 #define lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f)   \
739 {                                                               \
740         uint64_t signature10, signature11;                      \
741         uint32_t bucket10_index, bucket11_index;                \
742                                                                 \
743         signature10 = RTE_MBUF_METADATA_UINT32(mbuf10, f->signature_offset);\
744         bucket10_index = signature10 & (f->n_buckets - 1);      \
745         bucket10 = (struct rte_bucket_4_8 *)                    \
746                 &f->memory[bucket10_index * f->bucket_size];    \
747         rte_prefetch0(bucket10);                                \
748                                                                 \
749         signature11 = RTE_MBUF_METADATA_UINT32(mbuf11, f->signature_offset);\
750         bucket11_index = signature11 & (f->n_buckets - 1);      \
751         bucket11 = (struct rte_bucket_4_8 *)                    \
752                 &f->memory[bucket11_index * f->bucket_size];    \
753         rte_prefetch0(bucket11);                                \
754 }
755
756 #define lookup2_stage1_dosig(mbuf10, mbuf11, bucket10, bucket11, f)\
757 {                                                               \
758         uint64_t *key10, *key11;                                \
759         uint64_t hash_offset_buffer10;                          \
760         uint64_t hash_offset_buffer11;                          \
761         uint64_t signature10, signature11;                      \
762         uint32_t bucket10_index, bucket11_index;                \
763         rte_table_hash_op_hash f_hash = f->f_hash;              \
764         uint64_t seed = f->seed;                                \
765         uint32_t key_offset = f->key_offset;                    \
766                                                                 \
767         key10 = RTE_MBUF_METADATA_UINT64_PTR(mbuf10, key_offset);\
768         key11 = RTE_MBUF_METADATA_UINT64_PTR(mbuf11, key_offset);\
769         hash_offset_buffer10 = *key10 & f->key_mask;            \
770         hash_offset_buffer11 = *key11 & f->key_mask;            \
771                                                                 \
772         signature10 = f_hash(&hash_offset_buffer10,             \
773                 RTE_TABLE_HASH_KEY_SIZE, seed);                 \
774         bucket10_index = signature10 & (f->n_buckets - 1);      \
775         bucket10 = (struct rte_bucket_4_8 *)                    \
776                 &f->memory[bucket10_index * f->bucket_size];    \
777         rte_prefetch0(bucket10);                                \
778                                                                 \
779         signature11 = f_hash(&hash_offset_buffer11,             \
780                 RTE_TABLE_HASH_KEY_SIZE, seed);                 \
781         bucket11_index = signature11 & (f->n_buckets - 1);      \
782         bucket11 = (struct rte_bucket_4_8 *)                    \
783                 &f->memory[bucket11_index * f->bucket_size];    \
784         rte_prefetch0(bucket11);                                \
785 }
786
787 #define lookup2_stage2_lru(pkt20_index, pkt21_index, mbuf20, mbuf21,\
788         bucket20, bucket21, pkts_mask_out, entries, f)          \
789 {                                                               \
790         void *a20, *a21;                                        \
791         uint64_t pkt20_mask, pkt21_mask;                        \
792         uint64_t *key20, *key21;                                \
793         uint64_t hash_offset_buffer20;                          \
794         uint64_t hash_offset_buffer21;                          \
795         uint32_t pos20, pos21;                                  \
796                                                                 \
797         key20 = RTE_MBUF_METADATA_UINT64_PTR(mbuf20, f->key_offset);\
798         key21 = RTE_MBUF_METADATA_UINT64_PTR(mbuf21, f->key_offset);\
799         hash_offset_buffer20 = *key20 & f->key_mask;            \
800         hash_offset_buffer21 = *key21 & f->key_mask;            \
801                                                                 \
802         lookup_key8_cmp((&hash_offset_buffer20), bucket20, pos20);\
803         lookup_key8_cmp((&hash_offset_buffer21), bucket21, pos21);\
804                                                                 \
805         pkt20_mask = ((bucket20->signature >> pos20) & 1LLU) << pkt20_index;\
806         pkt21_mask = ((bucket21->signature >> pos21) & 1LLU) << pkt21_index;\
807         pkts_mask_out |= pkt20_mask | pkt21_mask;               \
808                                                                 \
809         a20 = (void *) &bucket20->data[pos20 * f->entry_size];  \
810         a21 = (void *) &bucket21->data[pos21 * f->entry_size];  \
811         rte_prefetch0(a20);                                     \
812         rte_prefetch0(a21);                                     \
813         entries[pkt20_index] = a20;                             \
814         entries[pkt21_index] = a21;                             \
815         lru_update(bucket20, pos20);                            \
816         lru_update(bucket21, pos21);                            \
817 }
818
819 #define lookup2_stage2_ext(pkt20_index, pkt21_index, mbuf20, mbuf21, bucket20, \
820         bucket21, pkts_mask_out, entries, buckets_mask, buckets, keys, f)\
821 {                                                               \
822         struct rte_bucket_4_8 *bucket20_next, *bucket21_next;   \
823         void *a20, *a21;                                        \
824         uint64_t pkt20_mask, pkt21_mask, bucket20_mask, bucket21_mask;\
825         uint64_t *key20, *key21;                                \
826         uint64_t hash_offset_buffer20;                          \
827         uint64_t hash_offset_buffer21;                          \
828         uint32_t pos20, pos21;                                  \
829                                                                 \
830         key20 = RTE_MBUF_METADATA_UINT64_PTR(mbuf20, f->key_offset);\
831         key21 = RTE_MBUF_METADATA_UINT64_PTR(mbuf21, f->key_offset);\
832         hash_offset_buffer20 = *key20 & f->key_mask;            \
833         hash_offset_buffer21 = *key21 & f->key_mask;            \
834                                                                 \
835         lookup_key8_cmp((&hash_offset_buffer20), bucket20, pos20);\
836         lookup_key8_cmp((&hash_offset_buffer21), bucket21, pos21);\
837                                                                 \
838         pkt20_mask = ((bucket20->signature >> pos20) & 1LLU) << pkt20_index;\
839         pkt21_mask = ((bucket21->signature >> pos21) & 1LLU) << pkt21_index;\
840         pkts_mask_out |= pkt20_mask | pkt21_mask;               \
841                                                                 \
842         a20 = (void *) &bucket20->data[pos20 * f->entry_size];  \
843         a21 = (void *) &bucket21->data[pos21 * f->entry_size];  \
844         rte_prefetch0(a20);                                     \
845         rte_prefetch0(a21);                                     \
846         entries[pkt20_index] = a20;                             \
847         entries[pkt21_index] = a21;                             \
848                                                                 \
849         bucket20_mask = (~pkt20_mask) & (bucket20->next_valid << pkt20_index);\
850         bucket21_mask = (~pkt21_mask) & (bucket21->next_valid << pkt21_index);\
851         buckets_mask |= bucket20_mask | bucket21_mask;          \
852         bucket20_next = bucket20->next;                         \
853         bucket21_next = bucket21->next;                         \
854         buckets[pkt20_index] = bucket20_next;                   \
855         buckets[pkt21_index] = bucket21_next;                   \
856         keys[pkt20_index] = key20;                              \
857         keys[pkt21_index] = key21;                              \
858 }
859
860 static int
861 rte_table_hash_lookup_key8_lru(
862         void *table,
863         struct rte_mbuf **pkts,
864         uint64_t pkts_mask,
865         uint64_t *lookup_hit_mask,
866         void **entries)
867 {
868         struct rte_table_hash *f = (struct rte_table_hash *) table;
869         struct rte_bucket_4_8 *bucket10, *bucket11, *bucket20, *bucket21;
870         struct rte_mbuf *mbuf00, *mbuf01, *mbuf10, *mbuf11, *mbuf20, *mbuf21;
871         uint32_t pkt00_index, pkt01_index, pkt10_index,
872                         pkt11_index, pkt20_index, pkt21_index;
873         uint64_t pkts_mask_out = 0;
874
875         __rte_unused uint32_t n_pkts_in = __builtin_popcountll(pkts_mask);
876         RTE_TABLE_HASH_KEY8_STATS_PKTS_IN_ADD(f, n_pkts_in);
877
878         /* Cannot run the pipeline with less than 5 packets */
879         if (__builtin_popcountll(pkts_mask) < 5) {
880                 for ( ; pkts_mask; ) {
881                         struct rte_bucket_4_8 *bucket;
882                         struct rte_mbuf *mbuf;
883                         uint32_t pkt_index;
884
885                         lookup1_stage0(pkt_index, mbuf, pkts, pkts_mask);
886                         lookup1_stage1(mbuf, bucket, f);
887                         lookup1_stage2_lru(pkt_index, mbuf, bucket,
888                                         pkts_mask_out, entries, f);
889                 }
890
891                 *lookup_hit_mask = pkts_mask_out;
892                 RTE_TABLE_HASH_KEY8_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in - __builtin_popcountll(pkts_mask_out));
893                 return 0;
894         }
895
896         /*
897          * Pipeline fill
898          *
899          */
900         /* Pipeline stage 0 */
901         lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
902                 pkts_mask);
903
904         /* Pipeline feed */
905         mbuf10 = mbuf00;
906         mbuf11 = mbuf01;
907         pkt10_index = pkt00_index;
908         pkt11_index = pkt01_index;
909
910         /* Pipeline stage 0 */
911         lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
912                 pkts_mask);
913
914         /* Pipeline stage 1 */
915         lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f);
916
917         /*
918          * Pipeline run
919          *
920          */
921         for ( ; pkts_mask; ) {
922                 /* Pipeline feed */
923                 bucket20 = bucket10;
924                 bucket21 = bucket11;
925                 mbuf20 = mbuf10;
926                 mbuf21 = mbuf11;
927                 mbuf10 = mbuf00;
928                 mbuf11 = mbuf01;
929                 pkt20_index = pkt10_index;
930                 pkt21_index = pkt11_index;
931                 pkt10_index = pkt00_index;
932                 pkt11_index = pkt01_index;
933
934                 /* Pipeline stage 0 */
935                 lookup2_stage0_with_odd_support(pkt00_index, pkt01_index,
936                         mbuf00, mbuf01, pkts, pkts_mask);
937
938                 /* Pipeline stage 1 */
939                 lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f);
940
941                 /* Pipeline stage 2 */
942                 lookup2_stage2_lru(pkt20_index, pkt21_index, mbuf20, mbuf21,
943                         bucket20, bucket21, pkts_mask_out, entries, f);
944         }
945
946         /*
947          * Pipeline flush
948          *
949          */
950         /* Pipeline feed */
951         bucket20 = bucket10;
952         bucket21 = bucket11;
953         mbuf20 = mbuf10;
954         mbuf21 = mbuf11;
955         mbuf10 = mbuf00;
956         mbuf11 = mbuf01;
957         pkt20_index = pkt10_index;
958         pkt21_index = pkt11_index;
959         pkt10_index = pkt00_index;
960         pkt11_index = pkt01_index;
961
962         /* Pipeline stage 1 */
963         lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f);
964
965         /* Pipeline stage 2 */
966         lookup2_stage2_lru(pkt20_index, pkt21_index, mbuf20, mbuf21,
967                 bucket20, bucket21, pkts_mask_out, entries, f);
968
969         /* Pipeline feed */
970         bucket20 = bucket10;
971         bucket21 = bucket11;
972         mbuf20 = mbuf10;
973         mbuf21 = mbuf11;
974         pkt20_index = pkt10_index;
975         pkt21_index = pkt11_index;
976
977         /* Pipeline stage 2 */
978         lookup2_stage2_lru(pkt20_index, pkt21_index, mbuf20, mbuf21,
979                 bucket20, bucket21, pkts_mask_out, entries, f);
980
981         *lookup_hit_mask = pkts_mask_out;
982         RTE_TABLE_HASH_KEY8_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in - __builtin_popcountll(pkts_mask_out));
983         return 0;
984 } /* rte_table_hash_lookup_key8_lru() */
985
986 static int
987 rte_table_hash_lookup_key8_lru_dosig(
988         void *table,
989         struct rte_mbuf **pkts,
990         uint64_t pkts_mask,
991         uint64_t *lookup_hit_mask,
992         void **entries)
993 {
994         struct rte_table_hash *f = (struct rte_table_hash *) table;
995         struct rte_bucket_4_8 *bucket10, *bucket11, *bucket20, *bucket21;
996         struct rte_mbuf *mbuf00, *mbuf01, *mbuf10, *mbuf11, *mbuf20, *mbuf21;
997         uint32_t pkt00_index, pkt01_index, pkt10_index;
998         uint32_t pkt11_index, pkt20_index, pkt21_index;
999         uint64_t pkts_mask_out = 0;
1000
1001         __rte_unused uint32_t n_pkts_in = __builtin_popcountll(pkts_mask);
1002         RTE_TABLE_HASH_KEY8_STATS_PKTS_IN_ADD(f, n_pkts_in);
1003
1004         /* Cannot run the pipeline with less than 5 packets */
1005         if (__builtin_popcountll(pkts_mask) < 5) {
1006                 for ( ; pkts_mask; ) {
1007                         struct rte_bucket_4_8 *bucket;
1008                         struct rte_mbuf *mbuf;
1009                         uint32_t pkt_index;
1010
1011                         lookup1_stage0(pkt_index, mbuf, pkts, pkts_mask);
1012                         lookup1_stage1_dosig(mbuf, bucket, f);
1013                         lookup1_stage2_lru(pkt_index, mbuf, bucket,
1014                                 pkts_mask_out, entries, f);
1015                 }
1016
1017                 *lookup_hit_mask = pkts_mask_out;
1018                 RTE_TABLE_HASH_KEY8_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in - __builtin_popcountll(pkts_mask_out));
1019                 return 0;
1020         }
1021
1022         /*
1023          * Pipeline fill
1024          *
1025          */
1026         /* Pipeline stage 0 */
1027         lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
1028                 pkts_mask);
1029
1030         /* Pipeline feed */
1031         mbuf10 = mbuf00;
1032         mbuf11 = mbuf01;
1033         pkt10_index = pkt00_index;
1034         pkt11_index = pkt01_index;
1035
1036         /* Pipeline stage 0 */
1037         lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
1038                 pkts_mask);
1039
1040         /* Pipeline stage 1 */
1041         lookup2_stage1_dosig(mbuf10, mbuf11, bucket10, bucket11, f);
1042
1043         /*
1044          * Pipeline run
1045          *
1046          */
1047         for ( ; pkts_mask; ) {
1048                 /* Pipeline feed */
1049                 bucket20 = bucket10;
1050                 bucket21 = bucket11;
1051                 mbuf20 = mbuf10;
1052                 mbuf21 = mbuf11;
1053                 mbuf10 = mbuf00;
1054                 mbuf11 = mbuf01;
1055                 pkt20_index = pkt10_index;
1056                 pkt21_index = pkt11_index;
1057                 pkt10_index = pkt00_index;
1058                 pkt11_index = pkt01_index;
1059
1060                 /* Pipeline stage 0 */
1061                 lookup2_stage0_with_odd_support(pkt00_index, pkt01_index,
1062                         mbuf00, mbuf01, pkts, pkts_mask);
1063
1064                 /* Pipeline stage 1 */
1065                 lookup2_stage1_dosig(mbuf10, mbuf11, bucket10, bucket11, f);
1066
1067                 /* Pipeline stage 2 */
1068                 lookup2_stage2_lru(pkt20_index, pkt21_index, mbuf20, mbuf21,
1069                         bucket20, bucket21, pkts_mask_out, entries, f);
1070         }
1071
1072         /*
1073          * Pipeline flush
1074          *
1075          */
1076         /* Pipeline feed */
1077         bucket20 = bucket10;
1078         bucket21 = bucket11;
1079         mbuf20 = mbuf10;
1080         mbuf21 = mbuf11;
1081         mbuf10 = mbuf00;
1082         mbuf11 = mbuf01;
1083         pkt20_index = pkt10_index;
1084         pkt21_index = pkt11_index;
1085         pkt10_index = pkt00_index;
1086         pkt11_index = pkt01_index;
1087
1088         /* Pipeline stage 1 */
1089         lookup2_stage1_dosig(mbuf10, mbuf11, bucket10, bucket11, f);
1090
1091         /* Pipeline stage 2 */
1092         lookup2_stage2_lru(pkt20_index, pkt21_index, mbuf20, mbuf21,
1093                 bucket20, bucket21, pkts_mask_out, entries, f);
1094
1095         /* Pipeline feed */
1096         bucket20 = bucket10;
1097         bucket21 = bucket11;
1098         mbuf20 = mbuf10;
1099         mbuf21 = mbuf11;
1100         pkt20_index = pkt10_index;
1101         pkt21_index = pkt11_index;
1102
1103         /* Pipeline stage 2 */
1104         lookup2_stage2_lru(pkt20_index, pkt21_index, mbuf20, mbuf21,
1105                 bucket20, bucket21, pkts_mask_out, entries, f);
1106
1107         *lookup_hit_mask = pkts_mask_out;
1108         RTE_TABLE_HASH_KEY8_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in - __builtin_popcountll(pkts_mask_out));
1109         return 0;
1110 } /* rte_table_hash_lookup_key8_lru_dosig() */
1111
1112 static int
1113 rte_table_hash_lookup_key8_ext(
1114         void *table,
1115         struct rte_mbuf **pkts,
1116         uint64_t pkts_mask,
1117         uint64_t *lookup_hit_mask,
1118         void **entries)
1119 {
1120         struct rte_table_hash *f = (struct rte_table_hash *) table;
1121         struct rte_bucket_4_8 *bucket10, *bucket11, *bucket20, *bucket21;
1122         struct rte_mbuf *mbuf00, *mbuf01, *mbuf10, *mbuf11, *mbuf20, *mbuf21;
1123         uint32_t pkt00_index, pkt01_index, pkt10_index;
1124         uint32_t pkt11_index, pkt20_index, pkt21_index;
1125         uint64_t pkts_mask_out = 0, buckets_mask = 0;
1126         struct rte_bucket_4_8 *buckets[RTE_PORT_IN_BURST_SIZE_MAX];
1127         uint64_t *keys[RTE_PORT_IN_BURST_SIZE_MAX];
1128
1129         __rte_unused uint32_t n_pkts_in = __builtin_popcountll(pkts_mask);
1130         RTE_TABLE_HASH_KEY8_STATS_PKTS_IN_ADD(f, n_pkts_in);
1131
1132         /* Cannot run the pipeline with less than 5 packets */
1133         if (__builtin_popcountll(pkts_mask) < 5) {
1134                 for ( ; pkts_mask; ) {
1135                         struct rte_bucket_4_8 *bucket;
1136                         struct rte_mbuf *mbuf;
1137                         uint32_t pkt_index;
1138
1139                         lookup1_stage0(pkt_index, mbuf, pkts, pkts_mask);
1140                         lookup1_stage1(mbuf, bucket, f);
1141                         lookup1_stage2_ext(pkt_index, mbuf, bucket,
1142                                 pkts_mask_out, entries, buckets_mask, buckets,
1143                                 keys, f);
1144                 }
1145
1146                 goto grind_next_buckets;
1147         }
1148
1149         /*
1150          * Pipeline fill
1151          *
1152          */
1153         /* Pipeline stage 0 */
1154         lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
1155                 pkts_mask);
1156
1157         /* Pipeline feed */
1158         mbuf10 = mbuf00;
1159         mbuf11 = mbuf01;
1160         pkt10_index = pkt00_index;
1161         pkt11_index = pkt01_index;
1162
1163         /* Pipeline stage 0 */
1164         lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
1165                 pkts_mask);
1166
1167         /* Pipeline stage 1 */
1168         lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f);
1169
1170         /*
1171          * Pipeline run
1172          *
1173          */
1174         for ( ; pkts_mask; ) {
1175                 /* Pipeline feed */
1176                 bucket20 = bucket10;
1177                 bucket21 = bucket11;
1178                 mbuf20 = mbuf10;
1179                 mbuf21 = mbuf11;
1180                 mbuf10 = mbuf00;
1181                 mbuf11 = mbuf01;
1182                 pkt20_index = pkt10_index;
1183                 pkt21_index = pkt11_index;
1184                 pkt10_index = pkt00_index;
1185                 pkt11_index = pkt01_index;
1186
1187                 /* Pipeline stage 0 */
1188                 lookup2_stage0_with_odd_support(pkt00_index, pkt01_index,
1189                         mbuf00, mbuf01, pkts, pkts_mask);
1190
1191                 /* Pipeline stage 1 */
1192                 lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f);
1193
1194                 /* Pipeline stage 2 */
1195                 lookup2_stage2_ext(pkt20_index, pkt21_index, mbuf20, mbuf21,
1196                         bucket20, bucket21, pkts_mask_out, entries,
1197                         buckets_mask, buckets, keys, f);
1198         }
1199
1200         /*
1201          * Pipeline flush
1202          *
1203          */
1204         /* Pipeline feed */
1205         bucket20 = bucket10;
1206         bucket21 = bucket11;
1207         mbuf20 = mbuf10;
1208         mbuf21 = mbuf11;
1209         mbuf10 = mbuf00;
1210         mbuf11 = mbuf01;
1211         pkt20_index = pkt10_index;
1212         pkt21_index = pkt11_index;
1213         pkt10_index = pkt00_index;
1214         pkt11_index = pkt01_index;
1215
1216         /* Pipeline stage 1 */
1217         lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f);
1218
1219         /* Pipeline stage 2 */
1220         lookup2_stage2_ext(pkt20_index, pkt21_index, mbuf20, mbuf21,
1221                 bucket20, bucket21, pkts_mask_out, entries,
1222                 buckets_mask, buckets, keys, f);
1223
1224         /* Pipeline feed */
1225         bucket20 = bucket10;
1226         bucket21 = bucket11;
1227         mbuf20 = mbuf10;
1228         mbuf21 = mbuf11;
1229         pkt20_index = pkt10_index;
1230         pkt21_index = pkt11_index;
1231
1232         /* Pipeline stage 2 */
1233         lookup2_stage2_ext(pkt20_index, pkt21_index, mbuf20, mbuf21,
1234                 bucket20, bucket21, pkts_mask_out, entries,
1235                 buckets_mask, buckets, keys, f);
1236
1237 grind_next_buckets:
1238         /* Grind next buckets */
1239         for ( ; buckets_mask; ) {
1240                 uint64_t buckets_mask_next = 0;
1241
1242                 for ( ; buckets_mask; ) {
1243                         uint64_t pkt_mask;
1244                         uint32_t pkt_index;
1245
1246                         pkt_index = __builtin_ctzll(buckets_mask);
1247                         pkt_mask = 1LLU << pkt_index;
1248                         buckets_mask &= ~pkt_mask;
1249
1250                         lookup_grinder(pkt_index, buckets, keys, pkts_mask_out,
1251                                 entries, buckets_mask_next, f);
1252                 }
1253
1254                 buckets_mask = buckets_mask_next;
1255         }
1256
1257         *lookup_hit_mask = pkts_mask_out;
1258         RTE_TABLE_HASH_KEY8_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in - __builtin_popcountll(pkts_mask_out));
1259         return 0;
1260 } /* rte_table_hash_lookup_key8_ext() */
1261
1262 static int
1263 rte_table_hash_lookup_key8_ext_dosig(
1264         void *table,
1265         struct rte_mbuf **pkts,
1266         uint64_t pkts_mask,
1267         uint64_t *lookup_hit_mask,
1268         void **entries)
1269 {
1270         struct rte_table_hash *f = (struct rte_table_hash *) table;
1271         struct rte_bucket_4_8 *bucket10, *bucket11, *bucket20, *bucket21;
1272         struct rte_mbuf *mbuf00, *mbuf01, *mbuf10, *mbuf11, *mbuf20, *mbuf21;
1273         uint32_t pkt00_index, pkt01_index, pkt10_index;
1274         uint32_t pkt11_index, pkt20_index, pkt21_index;
1275         uint64_t pkts_mask_out = 0, buckets_mask = 0;
1276         struct rte_bucket_4_8 *buckets[RTE_PORT_IN_BURST_SIZE_MAX];
1277         uint64_t *keys[RTE_PORT_IN_BURST_SIZE_MAX];
1278
1279         __rte_unused uint32_t n_pkts_in = __builtin_popcountll(pkts_mask);
1280         RTE_TABLE_HASH_KEY8_STATS_PKTS_IN_ADD(f, n_pkts_in);
1281
1282         /* Cannot run the pipeline with less than 5 packets */
1283         if (__builtin_popcountll(pkts_mask) < 5) {
1284                 for ( ; pkts_mask; ) {
1285                         struct rte_bucket_4_8 *bucket;
1286                         struct rte_mbuf *mbuf;
1287                         uint32_t pkt_index;
1288
1289                         lookup1_stage0(pkt_index, mbuf, pkts, pkts_mask);
1290                         lookup1_stage1_dosig(mbuf, bucket, f);
1291                         lookup1_stage2_ext(pkt_index, mbuf, bucket,
1292                                 pkts_mask_out, entries, buckets_mask,
1293                                 buckets, keys, f);
1294                 }
1295
1296                 goto grind_next_buckets;
1297         }
1298
1299         /*
1300          * Pipeline fill
1301          *
1302          */
1303         /* Pipeline stage 0 */
1304         lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
1305                 pkts_mask);
1306
1307         /* Pipeline feed */
1308         mbuf10 = mbuf00;
1309         mbuf11 = mbuf01;
1310         pkt10_index = pkt00_index;
1311         pkt11_index = pkt01_index;
1312
1313         /* Pipeline stage 0 */
1314         lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
1315                 pkts_mask);
1316
1317         /* Pipeline stage 1 */
1318         lookup2_stage1_dosig(mbuf10, mbuf11, bucket10, bucket11, f);
1319
1320         /*
1321          * Pipeline run
1322          *
1323          */
1324         for ( ; pkts_mask; ) {
1325                 /* Pipeline feed */
1326                 bucket20 = bucket10;
1327                 bucket21 = bucket11;
1328                 mbuf20 = mbuf10;
1329                 mbuf21 = mbuf11;
1330                 mbuf10 = mbuf00;
1331                 mbuf11 = mbuf01;
1332                 pkt20_index = pkt10_index;
1333                 pkt21_index = pkt11_index;
1334                 pkt10_index = pkt00_index;
1335                 pkt11_index = pkt01_index;
1336
1337                 /* Pipeline stage 0 */
1338                 lookup2_stage0_with_odd_support(pkt00_index, pkt01_index,
1339                         mbuf00, mbuf01, pkts, pkts_mask);
1340
1341                 /* Pipeline stage 1 */
1342                 lookup2_stage1_dosig(mbuf10, mbuf11, bucket10, bucket11, f);
1343
1344                 /* Pipeline stage 2 */
1345                 lookup2_stage2_ext(pkt20_index, pkt21_index, mbuf20, mbuf21,
1346                         bucket20, bucket21, pkts_mask_out, entries,
1347                         buckets_mask, buckets, keys, f);
1348         }
1349
1350         /*
1351          * Pipeline flush
1352          *
1353          */
1354         /* Pipeline feed */
1355         bucket20 = bucket10;
1356         bucket21 = bucket11;
1357         mbuf20 = mbuf10;
1358         mbuf21 = mbuf11;
1359         mbuf10 = mbuf00;
1360         mbuf11 = mbuf01;
1361         pkt20_index = pkt10_index;
1362         pkt21_index = pkt11_index;
1363         pkt10_index = pkt00_index;
1364         pkt11_index = pkt01_index;
1365
1366         /* Pipeline stage 1 */
1367         lookup2_stage1_dosig(mbuf10, mbuf11, bucket10, bucket11, f);
1368
1369         /* Pipeline stage 2 */
1370         lookup2_stage2_ext(pkt20_index, pkt21_index, mbuf20, mbuf21,
1371                 bucket20, bucket21, pkts_mask_out, entries,
1372                 buckets_mask, buckets, keys, f);
1373
1374         /* Pipeline feed */
1375         bucket20 = bucket10;
1376         bucket21 = bucket11;
1377         mbuf20 = mbuf10;
1378         mbuf21 = mbuf11;
1379         pkt20_index = pkt10_index;
1380         pkt21_index = pkt11_index;
1381
1382         /* Pipeline stage 2 */
1383         lookup2_stage2_ext(pkt20_index, pkt21_index, mbuf20, mbuf21,
1384                 bucket20, bucket21, pkts_mask_out, entries,
1385                 buckets_mask, buckets, keys, f);
1386
1387 grind_next_buckets:
1388         /* Grind next buckets */
1389         for ( ; buckets_mask; ) {
1390                 uint64_t buckets_mask_next = 0;
1391
1392                 for ( ; buckets_mask; ) {
1393                         uint64_t pkt_mask;
1394                         uint32_t pkt_index;
1395
1396                         pkt_index = __builtin_ctzll(buckets_mask);
1397                         pkt_mask = 1LLU << pkt_index;
1398                         buckets_mask &= ~pkt_mask;
1399
1400                         lookup_grinder(pkt_index, buckets, keys, pkts_mask_out,
1401                                 entries, buckets_mask_next, f);
1402                 }
1403
1404                 buckets_mask = buckets_mask_next;
1405         }
1406
1407         *lookup_hit_mask = pkts_mask_out;
1408         RTE_TABLE_HASH_KEY8_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in - __builtin_popcountll(pkts_mask_out));
1409         return 0;
1410 } /* rte_table_hash_lookup_key8_dosig_ext() */
1411
1412 static int
1413 rte_table_hash_key8_stats_read(void *table, struct rte_table_stats *stats, int clear)
1414 {
1415         struct rte_table_hash *t = (struct rte_table_hash *) table;
1416
1417         if (stats != NULL)
1418                 memcpy(stats, &t->stats, sizeof(t->stats));
1419
1420         if (clear)
1421                 memset(&t->stats, 0, sizeof(t->stats));
1422
1423         return 0;
1424 }
1425
1426 struct rte_table_ops rte_table_hash_key8_lru_ops = {
1427         .f_create = rte_table_hash_create_key8_lru,
1428         .f_free = rte_table_hash_free_key8_lru,
1429         .f_add = rte_table_hash_entry_add_key8_lru,
1430         .f_delete = rte_table_hash_entry_delete_key8_lru,
1431         .f_add_bulk = NULL,
1432         .f_delete_bulk = NULL,
1433         .f_lookup = rte_table_hash_lookup_key8_lru,
1434         .f_stats = rte_table_hash_key8_stats_read,
1435 };
1436
1437 struct rte_table_ops rte_table_hash_key8_lru_dosig_ops = {
1438         .f_create = rte_table_hash_create_key8_lru,
1439         .f_free = rte_table_hash_free_key8_lru,
1440         .f_add = rte_table_hash_entry_add_key8_lru,
1441         .f_delete = rte_table_hash_entry_delete_key8_lru,
1442         .f_add_bulk = NULL,
1443         .f_delete_bulk = NULL,
1444         .f_lookup = rte_table_hash_lookup_key8_lru_dosig,
1445         .f_stats = rte_table_hash_key8_stats_read,
1446 };
1447
1448 struct rte_table_ops rte_table_hash_key8_ext_ops = {
1449         .f_create = rte_table_hash_create_key8_ext,
1450         .f_free = rte_table_hash_free_key8_ext,
1451         .f_add = rte_table_hash_entry_add_key8_ext,
1452         .f_delete = rte_table_hash_entry_delete_key8_ext,
1453         .f_add_bulk = NULL,
1454         .f_delete_bulk = NULL,
1455         .f_lookup = rte_table_hash_lookup_key8_ext,
1456         .f_stats = rte_table_hash_key8_stats_read,
1457 };
1458
1459 struct rte_table_ops rte_table_hash_key8_ext_dosig_ops = {
1460         .f_create = rte_table_hash_create_key8_ext,
1461         .f_free = rte_table_hash_free_key8_ext,
1462         .f_add = rte_table_hash_entry_add_key8_ext,
1463         .f_delete = rte_table_hash_entry_delete_key8_ext,
1464         .f_add_bulk = NULL,
1465         .f_delete_bulk = NULL,
1466         .f_lookup = rte_table_hash_lookup_key8_ext_dosig,
1467         .f_stats = rte_table_hash_key8_stats_read,
1468 };