table: add unified params struct and mask-based hash func
[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_nomask 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) % 64) != 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 = 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 = 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 = 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) % 64) != 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 = 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 = 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 = 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, f)   \
572 {                                                               \
573         uint64_t pkt_mask;                                      \
574         uint32_t key_offset = f->key_offset;\
575                                                                 \
576         pkt0_index = __builtin_ctzll(pkts_mask);                \
577         pkt_mask = 1LLU << pkt0_index;                          \
578         pkts_mask &= ~pkt_mask;                                 \
579                                                                 \
580         mbuf0 = pkts[pkt0_index];                               \
581         rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf0, key_offset));  \
582 }
583
584 #define lookup1_stage1(mbuf1, bucket1, f)                       \
585 {                                                               \
586         uint64_t *key;                                          \
587         uint64_t signature;                                     \
588         uint32_t bucket_index;                                  \
589         uint64_t hash_key_buffer;                               \
590                                                                 \
591         key = RTE_MBUF_METADATA_UINT64_PTR(mbuf1, f->key_offset);\
592         hash_key_buffer = *key & f->key_mask;                   \
593         signature = f->f_hash(&hash_key_buffer,                 \
594                 RTE_TABLE_HASH_KEY_SIZE, f->seed);              \
595         bucket_index = signature & (f->n_buckets - 1);          \
596         bucket1 = (struct rte_bucket_4_8 *)                     \
597                 &f->memory[bucket_index * f->bucket_size];      \
598         rte_prefetch0(bucket1);                                 \
599 }
600
601 #define lookup1_stage2_lru(pkt2_index, mbuf2, bucket2,          \
602         pkts_mask_out, entries, f)                              \
603 {                                                               \
604         void *a;                                                \
605         uint64_t pkt_mask;                                      \
606         uint64_t *key;                                          \
607         uint32_t pos;                                           \
608         uint64_t hash_key_buffer;                               \
609                                                                 \
610         key = RTE_MBUF_METADATA_UINT64_PTR(mbuf2, f->key_offset);\
611         hash_key_buffer = key[0] & f->key_mask;                 \
612                                                                 \
613         lookup_key8_cmp((&hash_key_buffer), bucket2, pos);      \
614                                                                 \
615         pkt_mask = ((bucket2->signature >> pos) & 1LLU) << pkt2_index;\
616         pkts_mask_out |= pkt_mask;                              \
617                                                                 \
618         a = (void *) &bucket2->data[pos * f->entry_size];       \
619         rte_prefetch0(a);                                       \
620         entries[pkt2_index] = a;                                \
621         lru_update(bucket2, pos);                               \
622 }
623
624 #define lookup1_stage2_ext(pkt2_index, mbuf2, bucket2, pkts_mask_out,\
625         entries, buckets_mask, buckets, keys, f)                \
626 {                                                               \
627         struct rte_bucket_4_8 *bucket_next;                     \
628         void *a;                                                \
629         uint64_t pkt_mask, bucket_mask;                         \
630         uint64_t *key;                                          \
631         uint32_t pos;                                           \
632         uint64_t hash_key_buffer;                               \
633                                                                 \
634         key = RTE_MBUF_METADATA_UINT64_PTR(mbuf2, f->key_offset);\
635         hash_key_buffer = *key & f->key_mask;                   \
636                                                                 \
637         lookup_key8_cmp((&hash_key_buffer), bucket2, pos);      \
638                                                                 \
639         pkt_mask = ((bucket2->signature >> pos) & 1LLU) << pkt2_index;\
640         pkts_mask_out |= pkt_mask;                              \
641                                                                 \
642         a = (void *) &bucket2->data[pos * f->entry_size];       \
643         rte_prefetch0(a);                                       \
644         entries[pkt2_index] = a;                                \
645                                                                 \
646         bucket_mask = (~pkt_mask) & (bucket2->next_valid << pkt2_index);\
647         buckets_mask |= bucket_mask;                            \
648         bucket_next = bucket2->next;                            \
649         buckets[pkt2_index] = bucket_next;                      \
650         keys[pkt2_index] = key;                                 \
651 }
652
653 #define lookup_grinder(pkt_index, buckets, keys, pkts_mask_out, entries,\
654         buckets_mask, f)                                        \
655 {                                                               \
656         struct rte_bucket_4_8 *bucket, *bucket_next;            \
657         void *a;                                                \
658         uint64_t pkt_mask, bucket_mask;                         \
659         uint64_t *key;                                          \
660         uint32_t pos;                                           \
661         uint64_t hash_key_buffer;                               \
662                                                                 \
663         bucket = buckets[pkt_index];                            \
664         key = keys[pkt_index];                                  \
665         hash_key_buffer = (*key) & f->key_mask;                 \
666                                                                 \
667         lookup_key8_cmp((&hash_key_buffer), bucket, pos);       \
668                                                                 \
669         pkt_mask = ((bucket->signature >> pos) & 1LLU) << pkt_index;\
670         pkts_mask_out |= pkt_mask;                              \
671                                                                 \
672         a = (void *) &bucket->data[pos * f->entry_size];        \
673         rte_prefetch0(a);                                       \
674         entries[pkt_index] = a;                                 \
675                                                                 \
676         bucket_mask = (~pkt_mask) & (bucket->next_valid << pkt_index);\
677         buckets_mask |= bucket_mask;                            \
678         bucket_next = bucket->next;                             \
679         rte_prefetch0(bucket_next);                             \
680         buckets[pkt_index] = bucket_next;                       \
681         keys[pkt_index] = key;                                  \
682 }
683
684 #define lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01,\
685         pkts, pkts_mask, f)                                     \
686 {                                                               \
687         uint64_t pkt00_mask, pkt01_mask;                        \
688         uint32_t key_offset = f->key_offset;            \
689                                                                 \
690         pkt00_index = __builtin_ctzll(pkts_mask);               \
691         pkt00_mask = 1LLU << pkt00_index;                       \
692         pkts_mask &= ~pkt00_mask;                               \
693                                                                 \
694         mbuf00 = pkts[pkt00_index];                             \
695         rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf00, key_offset));\
696                                                                 \
697         pkt01_index = __builtin_ctzll(pkts_mask);               \
698         pkt01_mask = 1LLU << pkt01_index;                       \
699         pkts_mask &= ~pkt01_mask;                               \
700                                                                 \
701         mbuf01 = pkts[pkt01_index];                             \
702         rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf01, key_offset));\
703 }
704
705 #define lookup2_stage0_with_odd_support(pkt00_index, pkt01_index,\
706         mbuf00, mbuf01, pkts, pkts_mask, f)                     \
707 {                                                               \
708         uint64_t pkt00_mask, pkt01_mask;                        \
709         uint32_t key_offset = f->key_offset;            \
710                                                                 \
711         pkt00_index = __builtin_ctzll(pkts_mask);               \
712         pkt00_mask = 1LLU << pkt00_index;                       \
713         pkts_mask &= ~pkt00_mask;                               \
714                                                                 \
715         mbuf00 = pkts[pkt00_index];                             \
716         rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf00, key_offset));\
717                                                                 \
718         pkt01_index = __builtin_ctzll(pkts_mask);               \
719         if (pkts_mask == 0)                                     \
720                 pkt01_index = pkt00_index;                      \
721                                                                 \
722         pkt01_mask = 1LLU << pkt01_index;                       \
723         pkts_mask &= ~pkt01_mask;                               \
724                                                                 \
725         mbuf01 = pkts[pkt01_index];                             \
726         rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf01, key_offset));\
727 }
728
729 #define lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f)\
730 {                                                               \
731         uint64_t *key10, *key11;                                \
732         uint64_t hash_offset_buffer10;                          \
733         uint64_t hash_offset_buffer11;                          \
734         uint64_t signature10, signature11;                      \
735         uint32_t bucket10_index, bucket11_index;                \
736         rte_table_hash_op_hash_nomask f_hash = f->f_hash;               \
737         uint64_t seed = f->seed;                                \
738         uint32_t key_offset = f->key_offset;                    \
739                                                                 \
740         key10 = RTE_MBUF_METADATA_UINT64_PTR(mbuf10, key_offset);\
741         key11 = RTE_MBUF_METADATA_UINT64_PTR(mbuf11, key_offset);\
742         hash_offset_buffer10 = *key10 & f->key_mask;            \
743         hash_offset_buffer11 = *key11 & f->key_mask;            \
744                                                                 \
745         signature10 = f_hash(&hash_offset_buffer10,             \
746                 RTE_TABLE_HASH_KEY_SIZE, seed);                 \
747         bucket10_index = signature10 & (f->n_buckets - 1);      \
748         bucket10 = (struct rte_bucket_4_8 *)                    \
749                 &f->memory[bucket10_index * f->bucket_size];    \
750         rte_prefetch0(bucket10);                                \
751                                                                 \
752         signature11 = f_hash(&hash_offset_buffer11,             \
753                 RTE_TABLE_HASH_KEY_SIZE, seed);                 \
754         bucket11_index = signature11 & (f->n_buckets - 1);      \
755         bucket11 = (struct rte_bucket_4_8 *)                    \
756                 &f->memory[bucket11_index * f->bucket_size];    \
757         rte_prefetch0(bucket11);                                \
758 }
759
760 #define lookup2_stage2_lru(pkt20_index, pkt21_index, mbuf20, mbuf21,\
761         bucket20, bucket21, pkts_mask_out, entries, f)          \
762 {                                                               \
763         void *a20, *a21;                                        \
764         uint64_t pkt20_mask, pkt21_mask;                        \
765         uint64_t *key20, *key21;                                \
766         uint64_t hash_offset_buffer20;                          \
767         uint64_t hash_offset_buffer21;                          \
768         uint32_t pos20, pos21;                                  \
769                                                                 \
770         key20 = RTE_MBUF_METADATA_UINT64_PTR(mbuf20, f->key_offset);\
771         key21 = RTE_MBUF_METADATA_UINT64_PTR(mbuf21, f->key_offset);\
772         hash_offset_buffer20 = *key20 & f->key_mask;            \
773         hash_offset_buffer21 = *key21 & f->key_mask;            \
774                                                                 \
775         lookup_key8_cmp((&hash_offset_buffer20), bucket20, pos20);\
776         lookup_key8_cmp((&hash_offset_buffer21), bucket21, pos21);\
777                                                                 \
778         pkt20_mask = ((bucket20->signature >> pos20) & 1LLU) << pkt20_index;\
779         pkt21_mask = ((bucket21->signature >> pos21) & 1LLU) << pkt21_index;\
780         pkts_mask_out |= pkt20_mask | pkt21_mask;               \
781                                                                 \
782         a20 = (void *) &bucket20->data[pos20 * f->entry_size];  \
783         a21 = (void *) &bucket21->data[pos21 * f->entry_size];  \
784         rte_prefetch0(a20);                                     \
785         rte_prefetch0(a21);                                     \
786         entries[pkt20_index] = a20;                             \
787         entries[pkt21_index] = a21;                             \
788         lru_update(bucket20, pos20);                            \
789         lru_update(bucket21, pos21);                            \
790 }
791
792 #define lookup2_stage2_ext(pkt20_index, pkt21_index, mbuf20, mbuf21, bucket20, \
793         bucket21, pkts_mask_out, entries, buckets_mask, buckets, keys, f)\
794 {                                                               \
795         struct rte_bucket_4_8 *bucket20_next, *bucket21_next;   \
796         void *a20, *a21;                                        \
797         uint64_t pkt20_mask, pkt21_mask, bucket20_mask, bucket21_mask;\
798         uint64_t *key20, *key21;                                \
799         uint64_t hash_offset_buffer20;                          \
800         uint64_t hash_offset_buffer21;                          \
801         uint32_t pos20, pos21;                                  \
802                                                                 \
803         key20 = RTE_MBUF_METADATA_UINT64_PTR(mbuf20, f->key_offset);\
804         key21 = RTE_MBUF_METADATA_UINT64_PTR(mbuf21, f->key_offset);\
805         hash_offset_buffer20 = *key20 & f->key_mask;            \
806         hash_offset_buffer21 = *key21 & f->key_mask;            \
807                                                                 \
808         lookup_key8_cmp((&hash_offset_buffer20), bucket20, pos20);\
809         lookup_key8_cmp((&hash_offset_buffer21), bucket21, pos21);\
810                                                                 \
811         pkt20_mask = ((bucket20->signature >> pos20) & 1LLU) << pkt20_index;\
812         pkt21_mask = ((bucket21->signature >> pos21) & 1LLU) << pkt21_index;\
813         pkts_mask_out |= pkt20_mask | pkt21_mask;               \
814                                                                 \
815         a20 = (void *) &bucket20->data[pos20 * f->entry_size];  \
816         a21 = (void *) &bucket21->data[pos21 * f->entry_size];  \
817         rte_prefetch0(a20);                                     \
818         rte_prefetch0(a21);                                     \
819         entries[pkt20_index] = a20;                             \
820         entries[pkt21_index] = a21;                             \
821                                                                 \
822         bucket20_mask = (~pkt20_mask) & (bucket20->next_valid << pkt20_index);\
823         bucket21_mask = (~pkt21_mask) & (bucket21->next_valid << pkt21_index);\
824         buckets_mask |= bucket20_mask | bucket21_mask;          \
825         bucket20_next = bucket20->next;                         \
826         bucket21_next = bucket21->next;                         \
827         buckets[pkt20_index] = bucket20_next;                   \
828         buckets[pkt21_index] = bucket21_next;                   \
829         keys[pkt20_index] = key20;                              \
830         keys[pkt21_index] = key21;                              \
831 }
832
833 static int
834 rte_table_hash_lookup_key8_lru(
835         void *table,
836         struct rte_mbuf **pkts,
837         uint64_t pkts_mask,
838         uint64_t *lookup_hit_mask,
839         void **entries)
840 {
841         struct rte_table_hash *f = (struct rte_table_hash *) table;
842         struct rte_bucket_4_8 *bucket10, *bucket11, *bucket20, *bucket21;
843         struct rte_mbuf *mbuf00, *mbuf01, *mbuf10, *mbuf11, *mbuf20, *mbuf21;
844         uint32_t pkt00_index, pkt01_index, pkt10_index;
845         uint32_t pkt11_index, pkt20_index, pkt21_index;
846         uint64_t pkts_mask_out = 0;
847
848         __rte_unused uint32_t n_pkts_in = __builtin_popcountll(pkts_mask);
849         RTE_TABLE_HASH_KEY8_STATS_PKTS_IN_ADD(f, n_pkts_in);
850
851         /* Cannot run the pipeline with less than 5 packets */
852         if (__builtin_popcountll(pkts_mask) < 5) {
853                 for ( ; pkts_mask; ) {
854                         struct rte_bucket_4_8 *bucket;
855                         struct rte_mbuf *mbuf;
856                         uint32_t pkt_index;
857
858                         lookup1_stage0(pkt_index, mbuf, pkts, pkts_mask, f);
859                         lookup1_stage1(mbuf, bucket, f);
860                         lookup1_stage2_lru(pkt_index, mbuf, bucket,
861                                 pkts_mask_out, entries, f);
862                 }
863
864                 *lookup_hit_mask = pkts_mask_out;
865                 RTE_TABLE_HASH_KEY8_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in - __builtin_popcountll(pkts_mask_out));
866                 return 0;
867         }
868
869         /*
870          * Pipeline fill
871          *
872          */
873         /* Pipeline stage 0 */
874         lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
875                 pkts_mask, f);
876
877         /* Pipeline feed */
878         mbuf10 = mbuf00;
879         mbuf11 = mbuf01;
880         pkt10_index = pkt00_index;
881         pkt11_index = pkt01_index;
882
883         /* Pipeline stage 0 */
884         lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
885                 pkts_mask, f);
886
887         /* Pipeline stage 1 */
888         lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f);
889
890         /*
891          * Pipeline run
892          *
893          */
894         for ( ; pkts_mask; ) {
895                 /* Pipeline feed */
896                 bucket20 = bucket10;
897                 bucket21 = bucket11;
898                 mbuf20 = mbuf10;
899                 mbuf21 = mbuf11;
900                 mbuf10 = mbuf00;
901                 mbuf11 = mbuf01;
902                 pkt20_index = pkt10_index;
903                 pkt21_index = pkt11_index;
904                 pkt10_index = pkt00_index;
905                 pkt11_index = pkt01_index;
906
907                 /* Pipeline stage 0 */
908                 lookup2_stage0_with_odd_support(pkt00_index, pkt01_index,
909                         mbuf00, mbuf01, pkts, pkts_mask, f);
910
911                 /* Pipeline stage 1 */
912                 lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f);
913
914                 /* Pipeline stage 2 */
915                 lookup2_stage2_lru(pkt20_index, pkt21_index, mbuf20, mbuf21,
916                         bucket20, bucket21, pkts_mask_out, entries, f);
917         }
918
919         /*
920          * Pipeline flush
921          *
922          */
923         /* Pipeline feed */
924         bucket20 = bucket10;
925         bucket21 = bucket11;
926         mbuf20 = mbuf10;
927         mbuf21 = mbuf11;
928         mbuf10 = mbuf00;
929         mbuf11 = mbuf01;
930         pkt20_index = pkt10_index;
931         pkt21_index = pkt11_index;
932         pkt10_index = pkt00_index;
933         pkt11_index = pkt01_index;
934
935         /* Pipeline stage 1 */
936         lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f);
937
938         /* Pipeline stage 2 */
939         lookup2_stage2_lru(pkt20_index, pkt21_index, mbuf20, mbuf21,
940                 bucket20, bucket21, pkts_mask_out, entries, f);
941
942         /* Pipeline feed */
943         bucket20 = bucket10;
944         bucket21 = bucket11;
945         mbuf20 = mbuf10;
946         mbuf21 = mbuf11;
947         pkt20_index = pkt10_index;
948         pkt21_index = pkt11_index;
949
950         /* Pipeline stage 2 */
951         lookup2_stage2_lru(pkt20_index, pkt21_index, mbuf20, mbuf21,
952                 bucket20, bucket21, pkts_mask_out, entries, f);
953
954         *lookup_hit_mask = pkts_mask_out;
955         RTE_TABLE_HASH_KEY8_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in - __builtin_popcountll(pkts_mask_out));
956         return 0;
957 } /* rte_table_hash_lookup_key8_lru() */
958
959 static int
960 rte_table_hash_lookup_key8_ext(
961         void *table,
962         struct rte_mbuf **pkts,
963         uint64_t pkts_mask,
964         uint64_t *lookup_hit_mask,
965         void **entries)
966 {
967         struct rte_table_hash *f = (struct rte_table_hash *) table;
968         struct rte_bucket_4_8 *bucket10, *bucket11, *bucket20, *bucket21;
969         struct rte_mbuf *mbuf00, *mbuf01, *mbuf10, *mbuf11, *mbuf20, *mbuf21;
970         uint32_t pkt00_index, pkt01_index, pkt10_index;
971         uint32_t pkt11_index, pkt20_index, pkt21_index;
972         uint64_t pkts_mask_out = 0, buckets_mask = 0;
973         struct rte_bucket_4_8 *buckets[RTE_PORT_IN_BURST_SIZE_MAX];
974         uint64_t *keys[RTE_PORT_IN_BURST_SIZE_MAX];
975
976         __rte_unused uint32_t n_pkts_in = __builtin_popcountll(pkts_mask);
977         RTE_TABLE_HASH_KEY8_STATS_PKTS_IN_ADD(f, n_pkts_in);
978
979         /* Cannot run the pipeline with less than 5 packets */
980         if (__builtin_popcountll(pkts_mask) < 5) {
981                 for ( ; pkts_mask; ) {
982                         struct rte_bucket_4_8 *bucket;
983                         struct rte_mbuf *mbuf;
984                         uint32_t pkt_index;
985
986                         lookup1_stage0(pkt_index, mbuf, pkts, pkts_mask, f);
987                         lookup1_stage1(mbuf, bucket, f);
988                         lookup1_stage2_ext(pkt_index, mbuf, bucket,
989                                 pkts_mask_out, entries, buckets_mask,
990                                 buckets, keys, f);
991                 }
992
993                 goto grind_next_buckets;
994         }
995
996         /*
997          * Pipeline fill
998          *
999          */
1000         /* Pipeline stage 0 */
1001         lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
1002                 pkts_mask, f);
1003
1004         /* Pipeline feed */
1005         mbuf10 = mbuf00;
1006         mbuf11 = mbuf01;
1007         pkt10_index = pkt00_index;
1008         pkt11_index = pkt01_index;
1009
1010         /* Pipeline stage 0 */
1011         lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
1012                 pkts_mask, f);
1013
1014         /* Pipeline stage 1 */
1015         lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f);
1016
1017         /*
1018          * Pipeline run
1019          *
1020          */
1021         for ( ; pkts_mask; ) {
1022                 /* Pipeline feed */
1023                 bucket20 = bucket10;
1024                 bucket21 = bucket11;
1025                 mbuf20 = mbuf10;
1026                 mbuf21 = mbuf11;
1027                 mbuf10 = mbuf00;
1028                 mbuf11 = mbuf01;
1029                 pkt20_index = pkt10_index;
1030                 pkt21_index = pkt11_index;
1031                 pkt10_index = pkt00_index;
1032                 pkt11_index = pkt01_index;
1033
1034                 /* Pipeline stage 0 */
1035                 lookup2_stage0_with_odd_support(pkt00_index, pkt01_index,
1036                         mbuf00, mbuf01, pkts, pkts_mask, f);
1037
1038                 /* Pipeline stage 1 */
1039                 lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f);
1040
1041                 /* Pipeline stage 2 */
1042                 lookup2_stage2_ext(pkt20_index, pkt21_index, mbuf20, mbuf21,
1043                         bucket20, bucket21, pkts_mask_out, entries,
1044                         buckets_mask, buckets, keys, f);
1045         }
1046
1047         /*
1048          * Pipeline flush
1049          *
1050          */
1051         /* Pipeline feed */
1052         bucket20 = bucket10;
1053         bucket21 = bucket11;
1054         mbuf20 = mbuf10;
1055         mbuf21 = mbuf11;
1056         mbuf10 = mbuf00;
1057         mbuf11 = mbuf01;
1058         pkt20_index = pkt10_index;
1059         pkt21_index = pkt11_index;
1060         pkt10_index = pkt00_index;
1061         pkt11_index = pkt01_index;
1062
1063         /* Pipeline stage 1 */
1064         lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f);
1065
1066         /* Pipeline stage 2 */
1067         lookup2_stage2_ext(pkt20_index, pkt21_index, mbuf20, mbuf21,
1068                 bucket20, bucket21, pkts_mask_out, entries,
1069                 buckets_mask, buckets, keys, f);
1070
1071         /* Pipeline feed */
1072         bucket20 = bucket10;
1073         bucket21 = bucket11;
1074         mbuf20 = mbuf10;
1075         mbuf21 = mbuf11;
1076         pkt20_index = pkt10_index;
1077         pkt21_index = pkt11_index;
1078
1079         /* Pipeline stage 2 */
1080         lookup2_stage2_ext(pkt20_index, pkt21_index, mbuf20, mbuf21,
1081                 bucket20, bucket21, pkts_mask_out, entries,
1082                 buckets_mask, buckets, keys, f);
1083
1084 grind_next_buckets:
1085         /* Grind next buckets */
1086         for ( ; buckets_mask; ) {
1087                 uint64_t buckets_mask_next = 0;
1088
1089                 for ( ; buckets_mask; ) {
1090                         uint64_t pkt_mask;
1091                         uint32_t pkt_index;
1092
1093                         pkt_index = __builtin_ctzll(buckets_mask);
1094                         pkt_mask = 1LLU << pkt_index;
1095                         buckets_mask &= ~pkt_mask;
1096
1097                         lookup_grinder(pkt_index, buckets, keys, pkts_mask_out,
1098                                 entries, buckets_mask_next, f);
1099                 }
1100
1101                 buckets_mask = buckets_mask_next;
1102         }
1103
1104         *lookup_hit_mask = pkts_mask_out;
1105         RTE_TABLE_HASH_KEY8_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in - __builtin_popcountll(pkts_mask_out));
1106         return 0;
1107 } /* rte_table_hash_lookup_key8_ext() */
1108
1109 static int
1110 rte_table_hash_key8_stats_read(void *table, struct rte_table_stats *stats, int clear)
1111 {
1112         struct rte_table_hash *t = table;
1113
1114         if (stats != NULL)
1115                 memcpy(stats, &t->stats, sizeof(t->stats));
1116
1117         if (clear)
1118                 memset(&t->stats, 0, sizeof(t->stats));
1119
1120         return 0;
1121 }
1122
1123 struct rte_table_ops rte_table_hash_key8_lru_ops = {
1124         .f_create = rte_table_hash_create_key8_lru,
1125         .f_free = rte_table_hash_free_key8_lru,
1126         .f_add = rte_table_hash_entry_add_key8_lru,
1127         .f_delete = rte_table_hash_entry_delete_key8_lru,
1128         .f_add_bulk = NULL,
1129         .f_delete_bulk = NULL,
1130         .f_lookup = rte_table_hash_lookup_key8_lru,
1131         .f_stats = rte_table_hash_key8_stats_read,
1132 };
1133
1134 struct rte_table_ops rte_table_hash_key8_ext_ops = {
1135         .f_create = rte_table_hash_create_key8_ext,
1136         .f_free = rte_table_hash_free_key8_ext,
1137         .f_add = rte_table_hash_entry_add_key8_ext,
1138         .f_delete = rte_table_hash_entry_delete_key8_ext,
1139         .f_add_bulk = NULL,
1140         .f_delete_bulk = NULL,
1141         .f_lookup = rte_table_hash_lookup_key8_ext,
1142         .f_stats = rte_table_hash_key8_stats_read,
1143 };