lib: fix cache alignment of structures
[dpdk.git] / lib / librte_table / rte_table_hash_ext.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
34 #include <string.h>
35 #include <stdio.h>
36
37 #include <rte_common.h>
38 #include <rte_mbuf.h>
39 #include <rte_memory.h>
40 #include <rte_malloc.h>
41 #include <rte_log.h>
42
43 #include "rte_table_hash.h"
44
45 #define KEYS_PER_BUCKET 4
46
47 struct bucket {
48         union {
49                 uintptr_t next;
50                 uint64_t lru_list;
51         };
52         uint16_t sig[KEYS_PER_BUCKET];
53         uint32_t key_pos[KEYS_PER_BUCKET];
54 };
55
56 #define BUCKET_NEXT(bucket)                                             \
57         ((void *) ((bucket)->next & (~1LU)))
58
59 #define BUCKET_NEXT_VALID(bucket)                                       \
60         ((bucket)->next & 1LU)
61
62 #define BUCKET_NEXT_SET(bucket, bucket_next)                            \
63 do                                                                      \
64         (bucket)->next = (((uintptr_t) ((void *) (bucket_next))) | 1LU);\
65 while (0)
66
67 #define BUCKET_NEXT_SET_NULL(bucket)                                    \
68 do                                                                      \
69         (bucket)->next = 0;                                             \
70 while (0)
71
72 #define BUCKET_NEXT_COPY(bucket, bucket2)                               \
73 do                                                                      \
74         (bucket)->next = (bucket2)->next;                               \
75 while (0)
76
77 struct grinder {
78         struct bucket *bkt;
79         uint64_t sig;
80         uint64_t match;
81         uint32_t key_index;
82 };
83
84 struct rte_table_hash {
85         /* Input parameters */
86         uint32_t key_size;
87         uint32_t entry_size;
88         uint32_t n_keys;
89         uint32_t n_buckets;
90         uint32_t n_buckets_ext;
91         rte_table_hash_op_hash f_hash;
92         uint64_t seed;
93         uint32_t signature_offset;
94         uint32_t key_offset;
95
96         /* Internal */
97         uint64_t bucket_mask;
98         uint32_t key_size_shl;
99         uint32_t data_size_shl;
100         uint32_t key_stack_tos;
101         uint32_t bkt_ext_stack_tos;
102
103         /* Grinder */
104         struct grinder grinders[RTE_PORT_IN_BURST_SIZE_MAX];
105
106         /* Tables */
107         struct bucket *buckets;
108         struct bucket *buckets_ext;
109         uint8_t *key_mem;
110         uint8_t *data_mem;
111         uint32_t *key_stack;
112         uint32_t *bkt_ext_stack;
113
114         /* Table memory */
115         uint8_t memory[0] __rte_cache_aligned;
116 };
117
118 static int
119 check_params_create(struct rte_table_hash_ext_params *params)
120 {
121         uint32_t n_buckets_min;
122
123         /* key_size */
124         if ((params->key_size == 0) ||
125                 (!rte_is_power_of_2(params->key_size))) {
126                 RTE_LOG(ERR, TABLE, "%s: key_size invalid value\n", __func__);
127                 return -EINVAL;
128         }
129
130         /* n_keys */
131         if ((params->n_keys == 0) ||
132                 (!rte_is_power_of_2(params->n_keys))) {
133                 RTE_LOG(ERR, TABLE, "%s: n_keys invalid value\n", __func__);
134                 return -EINVAL;
135         }
136
137         /* n_buckets */
138         n_buckets_min = (params->n_keys + KEYS_PER_BUCKET - 1) / params->n_keys;
139         if ((params->n_buckets == 0) ||
140                 (!rte_is_power_of_2(params->n_keys)) ||
141                 (params->n_buckets < n_buckets_min)) {
142                 RTE_LOG(ERR, TABLE, "%s: n_buckets invalid value\n", __func__);
143                 return -EINVAL;
144         }
145
146         /* f_hash */
147         if (params->f_hash == NULL) {
148                 RTE_LOG(ERR, TABLE, "%s: f_hash invalid value\n", __func__);
149                 return -EINVAL;
150         }
151
152         /* signature offset */
153         if ((params->signature_offset & 0x3) != 0) {
154                 RTE_LOG(ERR, TABLE, "%s: signature_offset invalid value\n",
155                         __func__);
156                 return -EINVAL;
157         }
158
159         /* key offset */
160         if ((params->key_offset & 0x7) != 0) {
161                 RTE_LOG(ERR, TABLE, "%s: key_offset invalid value\n", __func__);
162                 return -EINVAL;
163         }
164
165         return 0;
166 }
167
168 static void *
169 rte_table_hash_ext_create(void *params, int socket_id, uint32_t entry_size)
170 {
171         struct rte_table_hash_ext_params *p =
172                 (struct rte_table_hash_ext_params *) params;
173         struct rte_table_hash *t;
174         uint32_t total_size, table_meta_sz;
175         uint32_t bucket_sz, bucket_ext_sz, key_sz;
176         uint32_t key_stack_sz, bkt_ext_stack_sz, data_sz;
177         uint32_t bucket_offset, bucket_ext_offset, key_offset;
178         uint32_t key_stack_offset, bkt_ext_stack_offset, data_offset;
179         uint32_t i;
180
181         /* Check input parameters */
182         if ((check_params_create(p) != 0) ||
183                 (!rte_is_power_of_2(entry_size)) ||
184                 ((sizeof(struct rte_table_hash) % RTE_CACHE_LINE_SIZE) != 0) ||
185                 (sizeof(struct bucket) != (RTE_CACHE_LINE_SIZE / 2)))
186                 return NULL;
187
188         /* Memory allocation */
189         table_meta_sz = RTE_CACHE_LINE_ROUNDUP(sizeof(struct rte_table_hash));
190         bucket_sz = RTE_CACHE_LINE_ROUNDUP(p->n_buckets * sizeof(struct bucket));
191         bucket_ext_sz =
192                 RTE_CACHE_LINE_ROUNDUP(p->n_buckets_ext * sizeof(struct bucket));
193         key_sz = RTE_CACHE_LINE_ROUNDUP(p->n_keys * p->key_size);
194         key_stack_sz = RTE_CACHE_LINE_ROUNDUP(p->n_keys * sizeof(uint32_t));
195         bkt_ext_stack_sz =
196                 RTE_CACHE_LINE_ROUNDUP(p->n_buckets_ext * sizeof(uint32_t));
197         data_sz = RTE_CACHE_LINE_ROUNDUP(p->n_keys * entry_size);
198         total_size = table_meta_sz + bucket_sz + bucket_ext_sz + key_sz +
199                 key_stack_sz + bkt_ext_stack_sz + data_sz;
200
201         t = rte_zmalloc_socket("TABLE", total_size, RTE_CACHE_LINE_SIZE, socket_id);
202         if (t == NULL) {
203                 RTE_LOG(ERR, TABLE,
204                         "%s: Cannot allocate %u bytes for hash table\n",
205                         __func__, total_size);
206                 return NULL;
207         }
208         RTE_LOG(INFO, TABLE, "%s (%u-byte key): Hash table memory footprint is "
209                 "%u bytes\n", __func__, p->key_size, total_size);
210
211         /* Memory initialization */
212         t->key_size = p->key_size;
213         t->entry_size = entry_size;
214         t->n_keys = p->n_keys;
215         t->n_buckets = p->n_buckets;
216         t->n_buckets_ext = p->n_buckets_ext;
217         t->f_hash = p->f_hash;
218         t->seed = p->seed;
219         t->signature_offset = p->signature_offset;
220         t->key_offset = p->key_offset;
221
222         /* Internal */
223         t->bucket_mask = t->n_buckets - 1;
224         t->key_size_shl = __builtin_ctzl(p->key_size);
225         t->data_size_shl = __builtin_ctzl(entry_size);
226
227         /* Tables */
228         bucket_offset = 0;
229         bucket_ext_offset = bucket_offset + bucket_sz;
230         key_offset = bucket_ext_offset + bucket_ext_sz;
231         key_stack_offset = key_offset + key_sz;
232         bkt_ext_stack_offset = key_stack_offset + key_stack_sz;
233         data_offset = bkt_ext_stack_offset + bkt_ext_stack_sz;
234
235         t->buckets = (struct bucket *) &t->memory[bucket_offset];
236         t->buckets_ext = (struct bucket *) &t->memory[bucket_ext_offset];
237         t->key_mem = &t->memory[key_offset];
238         t->key_stack = (uint32_t *) &t->memory[key_stack_offset];
239         t->bkt_ext_stack = (uint32_t *) &t->memory[bkt_ext_stack_offset];
240         t->data_mem = &t->memory[data_offset];
241
242         /* Key stack */
243         for (i = 0; i < t->n_keys; i++)
244                 t->key_stack[i] = t->n_keys - 1 - i;
245         t->key_stack_tos = t->n_keys;
246
247         /* Bucket ext stack */
248         for (i = 0; i < t->n_buckets_ext; i++)
249                 t->bkt_ext_stack[i] = t->n_buckets_ext - 1 - i;
250         t->bkt_ext_stack_tos = t->n_buckets_ext;
251
252         return t;
253 }
254
255 static int
256 rte_table_hash_ext_free(void *table)
257 {
258         struct rte_table_hash *t = (struct rte_table_hash *) table;
259
260         /* Check input parameters */
261         if (t == NULL)
262                 return -EINVAL;
263
264         rte_free(t);
265         return 0;
266 }
267
268 static int
269 rte_table_hash_ext_entry_add(void *table, void *key, void *entry,
270         int *key_found, void **entry_ptr)
271 {
272         struct rte_table_hash *t = (struct rte_table_hash *) table;
273         struct bucket *bkt0, *bkt, *bkt_prev;
274         uint64_t sig;
275         uint32_t bkt_index, i;
276
277         sig = t->f_hash(key, t->key_size, t->seed);
278         bkt_index = sig & t->bucket_mask;
279         bkt0 = &t->buckets[bkt_index];
280         sig = (sig >> 16) | 1LLU;
281
282         /* Key is present in the bucket */
283         for (bkt = bkt0; bkt != NULL; bkt = BUCKET_NEXT(bkt))
284                 for (i = 0; i < KEYS_PER_BUCKET; i++) {
285                         uint64_t bkt_sig = (uint64_t) bkt->sig[i];
286                         uint32_t bkt_key_index = bkt->key_pos[i];
287                         uint8_t *bkt_key =
288                                 &t->key_mem[bkt_key_index << t->key_size_shl];
289
290                         if ((sig == bkt_sig) && (memcmp(key, bkt_key,
291                                 t->key_size) == 0)) {
292                                 uint8_t *data = &t->data_mem[bkt_key_index <<
293                                         t->data_size_shl];
294
295                                 memcpy(data, entry, t->entry_size);
296                                 *key_found = 1;
297                                 *entry_ptr = (void *) data;
298                                 return 0;
299                         }
300                 }
301
302         /* Key is not present in the bucket */
303         for (bkt_prev = NULL, bkt = bkt0; bkt != NULL; bkt_prev = bkt,
304                 bkt = BUCKET_NEXT(bkt))
305                 for (i = 0; i < KEYS_PER_BUCKET; i++) {
306                         uint64_t bkt_sig = (uint64_t) bkt->sig[i];
307
308                         if (bkt_sig == 0) {
309                                 uint32_t bkt_key_index;
310                                 uint8_t *bkt_key, *data;
311
312                                 /* Allocate new key */
313                                 if (t->key_stack_tos == 0) /* No free keys */
314                                         return -ENOSPC;
315
316                                 bkt_key_index = t->key_stack[
317                                         --t->key_stack_tos];
318
319                                 /* Install new key */
320                                 bkt_key = &t->key_mem[bkt_key_index <<
321                                         t->key_size_shl];
322                                 data = &t->data_mem[bkt_key_index <<
323                                         t->data_size_shl];
324
325                                 bkt->sig[i] = (uint16_t) sig;
326                                 bkt->key_pos[i] = bkt_key_index;
327                                 memcpy(bkt_key, key, t->key_size);
328                                 memcpy(data, entry, t->entry_size);
329
330                                 *key_found = 0;
331                                 *entry_ptr = (void *) data;
332                                 return 0;
333                         }
334                 }
335
336         /* Bucket full: extend bucket */
337         if ((t->bkt_ext_stack_tos > 0) && (t->key_stack_tos > 0)) {
338                 uint32_t bkt_key_index;
339                 uint8_t *bkt_key, *data;
340
341                 /* Allocate new bucket ext */
342                 bkt_index = t->bkt_ext_stack[--t->bkt_ext_stack_tos];
343                 bkt = &t->buckets_ext[bkt_index];
344
345                 /* Chain the new bucket ext */
346                 BUCKET_NEXT_SET(bkt_prev, bkt);
347                 BUCKET_NEXT_SET_NULL(bkt);
348
349                 /* Allocate new key */
350                 bkt_key_index = t->key_stack[--t->key_stack_tos];
351                 bkt_key = &t->key_mem[bkt_key_index << t->key_size_shl];
352
353                 data = &t->data_mem[bkt_key_index << t->data_size_shl];
354
355                 /* Install new key into bucket */
356                 bkt->sig[0] = (uint16_t) sig;
357                 bkt->key_pos[0] = bkt_key_index;
358                 memcpy(bkt_key, key, t->key_size);
359                 memcpy(data, entry, t->entry_size);
360
361                 *key_found = 0;
362                 *entry_ptr = (void *) data;
363                 return 0;
364         }
365
366         return -ENOSPC;
367 }
368
369 static int
370 rte_table_hash_ext_entry_delete(void *table, void *key, int *key_found,
371 void *entry)
372 {
373         struct rte_table_hash *t = (struct rte_table_hash *) table;
374         struct bucket *bkt0, *bkt, *bkt_prev;
375         uint64_t sig;
376         uint32_t bkt_index, i;
377
378         sig = t->f_hash(key, t->key_size, t->seed);
379         bkt_index = sig & t->bucket_mask;
380         bkt0 = &t->buckets[bkt_index];
381         sig = (sig >> 16) | 1LLU;
382
383         /* Key is present in the bucket */
384         for (bkt_prev = NULL, bkt = bkt0; bkt != NULL; bkt_prev = bkt,
385                 bkt = BUCKET_NEXT(bkt))
386                 for (i = 0; i < KEYS_PER_BUCKET; i++) {
387                         uint64_t bkt_sig = (uint64_t) bkt->sig[i];
388                         uint32_t bkt_key_index = bkt->key_pos[i];
389                         uint8_t *bkt_key = &t->key_mem[bkt_key_index <<
390                                 t->key_size_shl];
391
392                         if ((sig == bkt_sig) && (memcmp(key, bkt_key,
393                                 t->key_size) == 0)) {
394                                 uint8_t *data = &t->data_mem[bkt_key_index <<
395                                         t->data_size_shl];
396
397                                 /* Uninstall key from bucket */
398                                 bkt->sig[i] = 0;
399                                 *key_found = 1;
400                                 if (entry)
401                                         memcpy(entry, data, t->entry_size);
402
403                                 /* Free key */
404                                 t->key_stack[t->key_stack_tos++] =
405                                         bkt_key_index;
406
407                                 /*Check if bucket is unused */
408                                 if ((bkt_prev != NULL) &&
409                                     (bkt->sig[0] == 0) && (bkt->sig[1] == 0) &&
410                                     (bkt->sig[2] == 0) && (bkt->sig[3] == 0)) {
411                                         /* Unchain bucket */
412                                         BUCKET_NEXT_COPY(bkt_prev, bkt);
413
414                                         /* Clear bucket */
415                                         memset(bkt, 0, sizeof(struct bucket));
416
417                                         /* Free bucket back to buckets ext */
418                                         bkt_index = bkt - t->buckets_ext;
419                                         t->bkt_ext_stack[t->bkt_ext_stack_tos++]
420                                                 = bkt_index;
421                                 }
422
423                                 return 0;
424                         }
425                 }
426
427         /* Key is not present in the bucket */
428         *key_found = 0;
429         return 0;
430 }
431
432 static int rte_table_hash_ext_lookup_unoptimized(
433         void *table,
434         struct rte_mbuf **pkts,
435         uint64_t pkts_mask,
436         uint64_t *lookup_hit_mask,
437         void **entries,
438         int dosig)
439 {
440         struct rte_table_hash *t = (struct rte_table_hash *) table;
441         uint64_t pkts_mask_out = 0;
442
443         for ( ; pkts_mask; ) {
444                 struct bucket *bkt0, *bkt;
445                 struct rte_mbuf *pkt;
446                 uint8_t *key;
447                 uint64_t pkt_mask, sig;
448                 uint32_t pkt_index, bkt_index, i;
449
450                 pkt_index = __builtin_ctzll(pkts_mask);
451                 pkt_mask = 1LLU << pkt_index;
452                 pkts_mask &= ~pkt_mask;
453
454                 pkt = pkts[pkt_index];
455                 key = RTE_MBUF_METADATA_UINT8_PTR(pkt, t->key_offset);
456                 if (dosig)
457                         sig = (uint64_t) t->f_hash(key, t->key_size, t->seed);
458                 else
459                         sig = RTE_MBUF_METADATA_UINT32(pkt,
460                                 t->signature_offset);
461
462                 bkt_index = sig & t->bucket_mask;
463                 bkt0 = &t->buckets[bkt_index];
464                 sig = (sig >> 16) | 1LLU;
465
466                 /* Key is present in the bucket */
467                 for (bkt = bkt0; bkt != NULL; bkt = BUCKET_NEXT(bkt))
468                         for (i = 0; i < KEYS_PER_BUCKET; i++) {
469                                 uint64_t bkt_sig = (uint64_t) bkt->sig[i];
470                                 uint32_t bkt_key_index = bkt->key_pos[i];
471                                 uint8_t *bkt_key = &t->key_mem[bkt_key_index <<
472                                         t->key_size_shl];
473
474                                 if ((sig == bkt_sig) && (memcmp(key, bkt_key,
475                                         t->key_size) == 0)) {
476                                         uint8_t *data = &t->data_mem[
477                                         bkt_key_index << t->data_size_shl];
478
479                                         pkts_mask_out |= pkt_mask;
480                                         entries[pkt_index] = (void *) data;
481                                         break;
482                                 }
483                         }
484         }
485
486         *lookup_hit_mask = pkts_mask_out;
487         return 0;
488 }
489
490 /***
491  *
492  * mask = match bitmask
493  * match = at least one match
494  * match_many = more than one match
495  * match_pos = position of first match
496  *
497  *----------------------------------------
498  * mask          match   match_many       match_pos
499  *----------------------------------------
500  * 0000          0               0                        00
501  * 0001          1               0                        00
502  * 0010          1               0                        01
503  * 0011          1               1                        00
504  *----------------------------------------
505  * 0100          1               0                        10
506  * 0101          1               1                        00
507  * 0110          1               1                        01
508  * 0111          1               1                        00
509  *----------------------------------------
510  * 1000          1               0                        11
511  * 1001          1               1                        00
512  * 1010          1               1                        01
513  * 1011          1               1                        00
514  *----------------------------------------
515  * 1100          1               1                        10
516  * 1101          1               1                        00
517  * 1110          1               1                        01
518  * 1111          1               1                        00
519  *----------------------------------------
520  *
521  * match = 1111_1111_1111_1110
522  * match_many = 1111_1110_1110_1000
523  * match_pos = 0001_0010_0001_0011__0001_0010_0001_0000
524  *
525  * match = 0xFFFELLU
526  * match_many = 0xFEE8LLU
527  * match_pos = 0x12131210LLU
528  *
529  ***/
530
531 #define LUT_MATCH                                               0xFFFELLU
532 #define LUT_MATCH_MANY                                          0xFEE8LLU
533 #define LUT_MATCH_POS                                           0x12131210LLU
534
535 #define lookup_cmp_sig(mbuf_sig, bucket, match, match_many, match_pos)  \
536 {                                                                       \
537         uint64_t bucket_sig[4], mask[4], mask_all;                      \
538                                                                         \
539         bucket_sig[0] = bucket->sig[0];                                 \
540         bucket_sig[1] = bucket->sig[1];                                 \
541         bucket_sig[2] = bucket->sig[2];                                 \
542         bucket_sig[3] = bucket->sig[3];                                 \
543                                                                         \
544         bucket_sig[0] ^= mbuf_sig;                                      \
545         bucket_sig[1] ^= mbuf_sig;                                      \
546         bucket_sig[2] ^= mbuf_sig;                                      \
547         bucket_sig[3] ^= mbuf_sig;                                      \
548                                                                         \
549         mask[0] = 0;                                                    \
550         mask[1] = 0;                                                    \
551         mask[2] = 0;                                                    \
552         mask[3] = 0;                                                    \
553                                                                         \
554         if (bucket_sig[0] == 0)                                         \
555                 mask[0] = 1;                                            \
556         if (bucket_sig[1] == 0)                                         \
557                 mask[1] = 2;                                            \
558         if (bucket_sig[2] == 0)                                         \
559                 mask[2] = 4;                                            \
560         if (bucket_sig[3] == 0)                                         \
561                 mask[3] = 8;                                            \
562                                                                         \
563         mask_all = (mask[0] | mask[1]) | (mask[2] | mask[3]);           \
564                                                                         \
565         match = (LUT_MATCH >> mask_all) & 1;                            \
566         match_many = (LUT_MATCH_MANY >> mask_all) & 1;                  \
567         match_pos = (LUT_MATCH_POS >> (mask_all << 1)) & 3;             \
568 }
569
570 #define lookup_cmp_key(mbuf, key, match_key, f)                         \
571 {                                                                       \
572         uint64_t *pkt_key = RTE_MBUF_METADATA_UINT64_PTR(mbuf, f->key_offset);\
573         uint64_t *bkt_key = (uint64_t *) key;                           \
574                                                                         \
575         switch (f->key_size) {                                          \
576         case 8:                                                         \
577         {                                                               \
578                 uint64_t xor = pkt_key[0] ^ bkt_key[0];                 \
579                 match_key = 0;                                          \
580                 if (xor == 0)                                           \
581                         match_key = 1;                                  \
582         }                                                               \
583         break;                                                          \
584                                                                         \
585         case 16:                                                        \
586         {                                                               \
587                 uint64_t xor[2], or;                                    \
588                                                                         \
589                 xor[0] = pkt_key[0] ^ bkt_key[0];                       \
590                 xor[1] = pkt_key[1] ^ bkt_key[1];                       \
591                 or = xor[0] | xor[1];                                   \
592                 match_key = 0;                                          \
593                 if (or == 0)                                            \
594                         match_key = 1;                                  \
595         }                                                               \
596         break;                                                          \
597                                                                         \
598         case 32:                                                        \
599         {                                                               \
600                 uint64_t xor[4], or;                                    \
601                                                                         \
602                 xor[0] = pkt_key[0] ^ bkt_key[0];                       \
603                 xor[1] = pkt_key[1] ^ bkt_key[1];                       \
604                 xor[2] = pkt_key[2] ^ bkt_key[2];                       \
605                 xor[3] = pkt_key[3] ^ bkt_key[3];                       \
606                 or = xor[0] | xor[1] | xor[2] | xor[3];                 \
607                 match_key = 0;                                          \
608                 if (or == 0)                                            \
609                         match_key = 1;                                  \
610         }                                                               \
611         break;                                                          \
612                                                                         \
613         case 64:                                                        \
614         {                                                               \
615                 uint64_t xor[8], or;                                    \
616                                                                         \
617                 xor[0] = pkt_key[0] ^ bkt_key[0];                       \
618                 xor[1] = pkt_key[1] ^ bkt_key[1];                       \
619                 xor[2] = pkt_key[2] ^ bkt_key[2];                       \
620                 xor[3] = pkt_key[3] ^ bkt_key[3];                       \
621                 xor[4] = pkt_key[4] ^ bkt_key[4];                       \
622                 xor[5] = pkt_key[5] ^ bkt_key[5];                       \
623                 xor[6] = pkt_key[6] ^ bkt_key[6];                       \
624                 xor[7] = pkt_key[7] ^ bkt_key[7];                       \
625                 or = xor[0] | xor[1] | xor[2] | xor[3] |                \
626                         xor[4] | xor[5] | xor[6] | xor[7];              \
627                 match_key = 0;                                          \
628                 if (or == 0)                                            \
629                         match_key = 1;                                  \
630         }                                                               \
631         break;                                                          \
632                                                                         \
633         default:                                                        \
634                 match_key = 0;                                          \
635                 if (memcmp(pkt_key, bkt_key, f->key_size) == 0)         \
636                         match_key = 1;                                  \
637         }                                                               \
638 }
639
640 #define lookup2_stage0(t, g, pkts, pkts_mask, pkt00_index, pkt01_index) \
641 {                                                                       \
642         uint64_t pkt00_mask, pkt01_mask;                                \
643         struct rte_mbuf *mbuf00, *mbuf01;                               \
644                                                                         \
645         pkt00_index = __builtin_ctzll(pkts_mask);                       \
646         pkt00_mask = 1LLU << pkt00_index;                               \
647         pkts_mask &= ~pkt00_mask;                                       \
648         mbuf00 = pkts[pkt00_index];                                     \
649                                                                         \
650         pkt01_index = __builtin_ctzll(pkts_mask);                       \
651         pkt01_mask = 1LLU << pkt01_index;                               \
652         pkts_mask &= ~pkt01_mask;                                       \
653         mbuf01 = pkts[pkt01_index];                                     \
654                                                                         \
655         rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf00, 0));          \
656         rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf01, 0));          \
657 }
658
659 #define lookup2_stage0_with_odd_support(t, g, pkts, pkts_mask, pkt00_index, \
660         pkt01_index)                                                    \
661 {                                                                       \
662         uint64_t pkt00_mask, pkt01_mask;                                \
663         struct rte_mbuf *mbuf00, *mbuf01;                               \
664                                                                         \
665         pkt00_index = __builtin_ctzll(pkts_mask);                       \
666         pkt00_mask = 1LLU << pkt00_index;                               \
667         pkts_mask &= ~pkt00_mask;                                       \
668         mbuf00 = pkts[pkt00_index];                                     \
669                                                                         \
670         pkt01_index = __builtin_ctzll(pkts_mask);                       \
671         if (pkts_mask == 0)                                             \
672                 pkt01_index = pkt00_index;                              \
673         pkt01_mask = 1LLU << pkt01_index;                               \
674         pkts_mask &= ~pkt01_mask;                                       \
675         mbuf01 = pkts[pkt01_index];                                     \
676                                                                         \
677         rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf00, 0));          \
678         rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf01, 0));          \
679 }
680
681 #define lookup2_stage1(t, g, pkts, pkt10_index, pkt11_index)            \
682 {                                                                       \
683         struct grinder *g10, *g11;                                      \
684         uint64_t sig10, sig11, bkt10_index, bkt11_index;                \
685         struct rte_mbuf *mbuf10, *mbuf11;                               \
686         struct bucket *bkt10, *bkt11, *buckets = t->buckets;            \
687         uint64_t bucket_mask = t->bucket_mask;                          \
688         uint32_t signature_offset = t->signature_offset;                \
689                                                                         \
690         mbuf10 = pkts[pkt10_index];                                     \
691         sig10 = (uint64_t) RTE_MBUF_METADATA_UINT32(mbuf10, signature_offset);\
692         bkt10_index = sig10 & bucket_mask;                              \
693         bkt10 = &buckets[bkt10_index];                                  \
694                                                                         \
695         mbuf11 = pkts[pkt11_index];                                     \
696         sig11 = (uint64_t) RTE_MBUF_METADATA_UINT32(mbuf11, signature_offset);\
697         bkt11_index = sig11 & bucket_mask;                              \
698         bkt11 = &buckets[bkt11_index];                                  \
699                                                                         \
700         rte_prefetch0(bkt10);                                           \
701         rte_prefetch0(bkt11);                                           \
702                                                                         \
703         g10 = &g[pkt10_index];                                          \
704         g10->sig = sig10;                                               \
705         g10->bkt = bkt10;                                               \
706                                                                         \
707         g11 = &g[pkt11_index];                                          \
708         g11->sig = sig11;                                               \
709         g11->bkt = bkt11;                                               \
710 }
711
712 #define lookup2_stage1_dosig(t, g, pkts, pkt10_index, pkt11_index)      \
713 {                                                                       \
714         struct grinder *g10, *g11;                                      \
715         uint64_t sig10, sig11, bkt10_index, bkt11_index;                \
716         struct rte_mbuf *mbuf10, *mbuf11;                               \
717         struct bucket *bkt10, *bkt11, *buckets = t->buckets;            \
718         uint8_t *key10, *key11;                                         \
719         uint64_t bucket_mask = t->bucket_mask;                          \
720         rte_table_hash_op_hash f_hash = t->f_hash;                      \
721         uint64_t seed = t->seed;                                        \
722         uint32_t key_size = t->key_size;                                \
723         uint32_t key_offset = t->key_offset;                            \
724                                                                         \
725         mbuf10 = pkts[pkt10_index];                                     \
726         key10 = RTE_MBUF_METADATA_UINT8_PTR(mbuf10, key_offset);        \
727         sig10 = (uint64_t) f_hash(key10, key_size, seed);               \
728         bkt10_index = sig10 & bucket_mask;                              \
729         bkt10 = &buckets[bkt10_index];                                  \
730                                                                         \
731         mbuf11 = pkts[pkt11_index];                                     \
732         key11 = RTE_MBUF_METADATA_UINT8_PTR(mbuf11, key_offset);        \
733         sig11 = (uint64_t) f_hash(key11, key_size, seed);               \
734         bkt11_index = sig11 & bucket_mask;                              \
735         bkt11 = &buckets[bkt11_index];                                  \
736                                                                         \
737         rte_prefetch0(bkt10);                                           \
738         rte_prefetch0(bkt11);                                           \
739                                                                         \
740         g10 = &g[pkt10_index];                                          \
741         g10->sig = sig10;                                               \
742         g10->bkt = bkt10;                                               \
743                                                                         \
744         g11 = &g[pkt11_index];                                          \
745         g11->sig = sig11;                                               \
746         g11->bkt = bkt11;                                               \
747 }
748
749 #define lookup2_stage2(t, g, pkt20_index, pkt21_index, pkts_mask_match_many)\
750 {                                                                       \
751         struct grinder *g20, *g21;                                      \
752         uint64_t sig20, sig21;                                          \
753         struct bucket *bkt20, *bkt21;                                   \
754         uint8_t *key20, *key21, *key_mem = t->key_mem;                  \
755         uint64_t match20, match21, match_many20, match_many21;          \
756         uint64_t match_pos20, match_pos21;                              \
757         uint32_t key20_index, key21_index, key_size_shl = t->key_size_shl;\
758                                                                         \
759         g20 = &g[pkt20_index];                                          \
760         sig20 = g20->sig;                                               \
761         bkt20 = g20->bkt;                                               \
762         sig20 = (sig20 >> 16) | 1LLU;                                   \
763         lookup_cmp_sig(sig20, bkt20, match20, match_many20, match_pos20);\
764         match20 <<= pkt20_index;                                        \
765         match_many20 |= BUCKET_NEXT_VALID(bkt20);                       \
766         match_many20 <<= pkt20_index;                                   \
767         key20_index = bkt20->key_pos[match_pos20];                      \
768         key20 = &key_mem[key20_index << key_size_shl];                  \
769                                                                         \
770         g21 = &g[pkt21_index];                                          \
771         sig21 = g21->sig;                                               \
772         bkt21 = g21->bkt;                                               \
773         sig21 = (sig21 >> 16) | 1LLU;                                   \
774         lookup_cmp_sig(sig21, bkt21, match21, match_many21, match_pos21);\
775         match21 <<= pkt21_index;                                        \
776         match_many21 |= BUCKET_NEXT_VALID(bkt21);                       \
777         match_many21 <<= pkt21_index;                                   \
778         key21_index = bkt21->key_pos[match_pos21];                      \
779         key21 = &key_mem[key21_index << key_size_shl];                  \
780                                                                         \
781         rte_prefetch0(key20);                                           \
782         rte_prefetch0(key21);                                           \
783                                                                         \
784         pkts_mask_match_many |= match_many20 | match_many21;            \
785                                                                         \
786         g20->match = match20;                                           \
787         g20->key_index = key20_index;                                   \
788                                                                         \
789         g21->match = match21;                                           \
790         g21->key_index = key21_index;                                   \
791 }
792
793 #define lookup2_stage3(t, g, pkts, pkt30_index, pkt31_index, pkts_mask_out, \
794         entries)                                                        \
795 {                                                                       \
796         struct grinder *g30, *g31;                                      \
797         struct rte_mbuf *mbuf30, *mbuf31;                               \
798         uint8_t *key30, *key31, *key_mem = t->key_mem;                  \
799         uint8_t *data30, *data31, *data_mem = t->data_mem;              \
800         uint64_t match30, match31, match_key30, match_key31, match_keys;\
801         uint32_t key30_index, key31_index;                              \
802         uint32_t key_size_shl = t->key_size_shl;                        \
803         uint32_t data_size_shl = t->data_size_shl;                      \
804                                                                         \
805         mbuf30 = pkts[pkt30_index];                                     \
806         g30 = &g[pkt30_index];                                          \
807         match30 = g30->match;                                           \
808         key30_index = g30->key_index;                                   \
809         key30 = &key_mem[key30_index << key_size_shl];                  \
810         lookup_cmp_key(mbuf30, key30, match_key30, t);                  \
811         match_key30 <<= pkt30_index;                                    \
812         match_key30 &= match30;                                         \
813         data30 = &data_mem[key30_index << data_size_shl];               \
814         entries[pkt30_index] = data30;                                  \
815                                                                         \
816         mbuf31 = pkts[pkt31_index];                                     \
817         g31 = &g[pkt31_index];                                          \
818         match31 = g31->match;                                           \
819         key31_index = g31->key_index;                                   \
820         key31 = &key_mem[key31_index << key_size_shl];                  \
821         lookup_cmp_key(mbuf31, key31, match_key31, t);                  \
822         match_key31 <<= pkt31_index;                                    \
823         match_key31 &= match31;                                         \
824         data31 = &data_mem[key31_index << data_size_shl];               \
825         entries[pkt31_index] = data31;                                  \
826                                                                         \
827         rte_prefetch0(data30);                                          \
828         rte_prefetch0(data31);                                          \
829                                                                         \
830         match_keys = match_key30 | match_key31;                         \
831         pkts_mask_out |= match_keys;                                    \
832 }
833
834 /***
835 * The lookup function implements a 4-stage pipeline, with each stage processing
836 * two different packets. The purpose of pipelined implementation is to hide the
837 * latency of prefetching the data structures and loosen the data dependency
838 * between instructions.
839 *
840 *  p00  _______   p10  _______   p20  _______   p30  _______
841 *----->|       |----->|       |----->|       |----->|       |----->
842 *      |   0   |      |   1   |      |   2   |      |   3   |
843 *----->|_______|----->|_______|----->|_______|----->|_______|----->
844 *  p01            p11            p21            p31
845 *
846 * The naming convention is:
847 *    pXY = packet Y of stage X, X = 0 .. 3, Y = 0 .. 1
848 *
849 ***/
850 static int rte_table_hash_ext_lookup(
851         void *table,
852         struct rte_mbuf **pkts,
853         uint64_t pkts_mask,
854         uint64_t *lookup_hit_mask,
855         void **entries)
856 {
857         struct rte_table_hash *t = (struct rte_table_hash *) table;
858         struct grinder *g = t->grinders;
859         uint64_t pkt00_index, pkt01_index, pkt10_index, pkt11_index;
860         uint64_t pkt20_index, pkt21_index, pkt30_index, pkt31_index;
861         uint64_t pkts_mask_out = 0, pkts_mask_match_many = 0;
862         int status = 0;
863
864         /* Cannot run the pipeline with less than 7 packets */
865         if (__builtin_popcountll(pkts_mask) < 7)
866                 return rte_table_hash_ext_lookup_unoptimized(table, pkts,
867                         pkts_mask, lookup_hit_mask, entries, 0);
868
869         /* Pipeline stage 0 */
870         lookup2_stage0(t, g, pkts, pkts_mask, pkt00_index, pkt01_index);
871
872         /* Pipeline feed */
873         pkt10_index = pkt00_index;
874         pkt11_index = pkt01_index;
875
876         /* Pipeline stage 0 */
877         lookup2_stage0(t, g, pkts, pkts_mask, pkt00_index, pkt01_index);
878
879         /* Pipeline stage 1 */
880         lookup2_stage1(t, g, pkts, pkt10_index, pkt11_index);
881
882         /* Pipeline feed */
883         pkt20_index = pkt10_index;
884         pkt21_index = pkt11_index;
885         pkt10_index = pkt00_index;
886         pkt11_index = pkt01_index;
887
888         /* Pipeline stage 0 */
889         lookup2_stage0(t, g, pkts, pkts_mask, pkt00_index, pkt01_index);
890
891         /* Pipeline stage 1 */
892         lookup2_stage1(t, g, pkts, pkt10_index, pkt11_index);
893
894         /* Pipeline stage 2 */
895         lookup2_stage2(t, g, pkt20_index, pkt21_index, pkts_mask_match_many);
896
897         /*
898         * Pipeline run
899         *
900         */
901         for ( ; pkts_mask; ) {
902                 /* Pipeline feed */
903                 pkt30_index = pkt20_index;
904                 pkt31_index = pkt21_index;
905                 pkt20_index = pkt10_index;
906                 pkt21_index = pkt11_index;
907                 pkt10_index = pkt00_index;
908                 pkt11_index = pkt01_index;
909
910                 /* Pipeline stage 0 */
911                 lookup2_stage0_with_odd_support(t, g, pkts, pkts_mask,
912                         pkt00_index, pkt01_index);
913
914                 /* Pipeline stage 1 */
915                 lookup2_stage1(t, g, pkts, pkt10_index, pkt11_index);
916
917                 /* Pipeline stage 2 */
918                 lookup2_stage2(t, g, pkt20_index, pkt21_index,
919                         pkts_mask_match_many);
920
921                 /* Pipeline stage 3 */
922                 lookup2_stage3(t, g, pkts, pkt30_index, pkt31_index,
923                         pkts_mask_out, entries);
924         }
925
926         /* Pipeline feed */
927         pkt30_index = pkt20_index;
928         pkt31_index = pkt21_index;
929         pkt20_index = pkt10_index;
930         pkt21_index = pkt11_index;
931         pkt10_index = pkt00_index;
932         pkt11_index = pkt01_index;
933
934         /* Pipeline stage 1 */
935         lookup2_stage1(t, g, pkts, pkt10_index, pkt11_index);
936
937         /* Pipeline stage 2 */
938         lookup2_stage2(t, g, pkt20_index, pkt21_index, pkts_mask_match_many);
939
940         /* Pipeline stage 3 */
941         lookup2_stage3(t, g, pkts, pkt30_index, pkt31_index, pkts_mask_out,
942                 entries);
943
944         /* Pipeline feed */
945         pkt30_index = pkt20_index;
946         pkt31_index = pkt21_index;
947         pkt20_index = pkt10_index;
948         pkt21_index = pkt11_index;
949
950         /* Pipeline stage 2 */
951         lookup2_stage2(t, g, pkt20_index, pkt21_index, pkts_mask_match_many);
952
953         /* Pipeline stage 3 */
954         lookup2_stage3(t, g, pkts, pkt30_index, pkt31_index, pkts_mask_out,
955                 entries);
956
957         /* Pipeline feed */
958         pkt30_index = pkt20_index;
959         pkt31_index = pkt21_index;
960
961         /* Pipeline stage 3 */
962         lookup2_stage3(t, g, pkts, pkt30_index, pkt31_index, pkts_mask_out,
963                 entries);
964
965         /* Slow path */
966         pkts_mask_match_many &= ~pkts_mask_out;
967         if (pkts_mask_match_many) {
968                 uint64_t pkts_mask_out_slow = 0;
969
970                 status = rte_table_hash_ext_lookup_unoptimized(table, pkts,
971                         pkts_mask_match_many, &pkts_mask_out_slow, entries, 0);
972                 pkts_mask_out |= pkts_mask_out_slow;
973         }
974
975         *lookup_hit_mask = pkts_mask_out;
976         return status;
977 }
978
979 static int rte_table_hash_ext_lookup_dosig(
980         void *table,
981         struct rte_mbuf **pkts,
982         uint64_t pkts_mask,
983         uint64_t *lookup_hit_mask,
984         void **entries)
985 {
986         struct rte_table_hash *t = (struct rte_table_hash *) table;
987         struct grinder *g = t->grinders;
988         uint64_t pkt00_index, pkt01_index, pkt10_index, pkt11_index;
989         uint64_t pkt20_index, pkt21_index, pkt30_index, pkt31_index;
990         uint64_t pkts_mask_out = 0, pkts_mask_match_many = 0;
991         int status = 0;
992
993         /* Cannot run the pipeline with less than 7 packets */
994         if (__builtin_popcountll(pkts_mask) < 7)
995                 return rte_table_hash_ext_lookup_unoptimized(table, pkts,
996                         pkts_mask, lookup_hit_mask, entries, 1);
997
998         /* Pipeline stage 0 */
999         lookup2_stage0(t, g, pkts, pkts_mask, pkt00_index, pkt01_index);
1000
1001         /* Pipeline feed */
1002         pkt10_index = pkt00_index;
1003         pkt11_index = pkt01_index;
1004
1005         /* Pipeline stage 0 */
1006         lookup2_stage0(t, g, pkts, pkts_mask, pkt00_index, pkt01_index);
1007
1008         /* Pipeline stage 1 */
1009         lookup2_stage1_dosig(t, g, pkts, pkt10_index, pkt11_index);
1010
1011         /* Pipeline feed */
1012         pkt20_index = pkt10_index;
1013         pkt21_index = pkt11_index;
1014         pkt10_index = pkt00_index;
1015         pkt11_index = pkt01_index;
1016
1017         /* Pipeline stage 0 */
1018         lookup2_stage0(t, g, pkts, pkts_mask, pkt00_index, pkt01_index);
1019
1020         /* Pipeline stage 1 */
1021         lookup2_stage1_dosig(t, g, pkts, pkt10_index, pkt11_index);
1022
1023         /* Pipeline stage 2 */
1024         lookup2_stage2(t, g, pkt20_index, pkt21_index, pkts_mask_match_many);
1025
1026         /*
1027         * Pipeline run
1028         *
1029         */
1030         for ( ; pkts_mask; ) {
1031                 /* Pipeline feed */
1032                 pkt30_index = pkt20_index;
1033                 pkt31_index = pkt21_index;
1034                 pkt20_index = pkt10_index;
1035                 pkt21_index = pkt11_index;
1036                 pkt10_index = pkt00_index;
1037                 pkt11_index = pkt01_index;
1038
1039                 /* Pipeline stage 0 */
1040                 lookup2_stage0_with_odd_support(t, g, pkts, pkts_mask,
1041                         pkt00_index, pkt01_index);
1042
1043                 /* Pipeline stage 1 */
1044                 lookup2_stage1_dosig(t, g, pkts, pkt10_index, pkt11_index);
1045
1046                 /* Pipeline stage 2 */
1047                 lookup2_stage2(t, g, pkt20_index, pkt21_index,
1048                         pkts_mask_match_many);
1049
1050                 /* Pipeline stage 3 */
1051                 lookup2_stage3(t, g, pkts, pkt30_index, pkt31_index,
1052                         pkts_mask_out, entries);
1053         }
1054
1055         /* Pipeline feed */
1056         pkt30_index = pkt20_index;
1057         pkt31_index = pkt21_index;
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_dosig(t, g, pkts, pkt10_index, pkt11_index);
1065
1066         /* Pipeline stage 2 */
1067         lookup2_stage2(t, g, pkt20_index, pkt21_index, pkts_mask_match_many);
1068
1069         /* Pipeline stage 3 */
1070         lookup2_stage3(t, g, pkts, pkt30_index, pkt31_index, pkts_mask_out,
1071                 entries);
1072
1073         /* Pipeline feed */
1074         pkt30_index = pkt20_index;
1075         pkt31_index = pkt21_index;
1076         pkt20_index = pkt10_index;
1077         pkt21_index = pkt11_index;
1078
1079         /* Pipeline stage 2 */
1080         lookup2_stage2(t, g, pkt20_index, pkt21_index, pkts_mask_match_many);
1081
1082         /* Pipeline stage 3 */
1083         lookup2_stage3(t, g, pkts, pkt30_index, pkt31_index, pkts_mask_out,
1084                 entries);
1085
1086         /* Pipeline feed */
1087         pkt30_index = pkt20_index;
1088         pkt31_index = pkt21_index;
1089
1090         /* Pipeline stage 3 */
1091         lookup2_stage3(t, g, pkts, pkt30_index, pkt31_index, pkts_mask_out,
1092                 entries);
1093
1094         /* Slow path */
1095         pkts_mask_match_many &= ~pkts_mask_out;
1096         if (pkts_mask_match_many) {
1097                 uint64_t pkts_mask_out_slow = 0;
1098
1099                 status = rte_table_hash_ext_lookup_unoptimized(table, pkts,
1100                         pkts_mask_match_many, &pkts_mask_out_slow, entries, 1);
1101                 pkts_mask_out |= pkts_mask_out_slow;
1102         }
1103
1104         *lookup_hit_mask = pkts_mask_out;
1105         return status;
1106 }
1107
1108 struct rte_table_ops rte_table_hash_ext_ops      = {
1109         .f_create = rte_table_hash_ext_create,
1110         .f_free = rte_table_hash_ext_free,
1111         .f_add = rte_table_hash_ext_entry_add,
1112         .f_delete = rte_table_hash_ext_entry_delete,
1113         .f_lookup = rte_table_hash_ext_lookup,
1114 };
1115
1116 struct rte_table_ops rte_table_hash_ext_dosig_ops  = {
1117         .f_create = rte_table_hash_ext_create,
1118         .f_free = rte_table_hash_ext_free,
1119         .f_add = rte_table_hash_ext_entry_add,
1120         .f_delete = rte_table_hash_ext_entry_delete,
1121         .f_lookup = rte_table_hash_ext_lookup_dosig,
1122 };