doc: add Meson coding style to contributors guide
[dpdk.git] / lib / librte_table / rte_table_hash_key16.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2017 Intel Corporation
3  */
4 #include <string.h>
5 #include <stdio.h>
6
7 #include <rte_common.h>
8 #include <rte_mbuf.h>
9 #include <rte_memory.h>
10 #include <rte_malloc.h>
11 #include <rte_log.h>
12
13 #include "rte_table_hash.h"
14 #include "rte_lru.h"
15
16 #define KEY_SIZE                                                16
17
18 #define KEYS_PER_BUCKET                                 4
19
20 #define RTE_BUCKET_ENTRY_VALID                                          0x1LLU
21
22 #ifdef RTE_TABLE_STATS_COLLECT
23
24 #define RTE_TABLE_HASH_KEY16_STATS_PKTS_IN_ADD(table, val) \
25         table->stats.n_pkts_in += val
26 #define RTE_TABLE_HASH_KEY16_STATS_PKTS_LOOKUP_MISS(table, val) \
27         table->stats.n_pkts_lookup_miss += val
28
29 #else
30
31 #define RTE_TABLE_HASH_KEY16_STATS_PKTS_IN_ADD(table, val)
32 #define RTE_TABLE_HASH_KEY16_STATS_PKTS_LOOKUP_MISS(table, val)
33
34 #endif
35
36 #ifdef RTE_ARCH_64
37 struct rte_bucket_4_16 {
38         /* Cache line 0 */
39         uint64_t signature[4 + 1];
40         uint64_t lru_list;
41         struct rte_bucket_4_16 *next;
42         uint64_t next_valid;
43
44         /* Cache line 1 */
45         uint64_t key[4][2];
46
47         /* Cache line 2 */
48         uint8_t data[0];
49 };
50 #else
51 struct rte_bucket_4_16 {
52         /* Cache line 0 */
53         uint64_t signature[4 + 1];
54         uint64_t lru_list;
55         struct rte_bucket_4_16 *next;
56         uint32_t pad;
57         uint64_t next_valid;
58
59         /* Cache line 1 */
60         uint64_t key[4][2];
61
62         /* Cache line 2 */
63         uint8_t data[0];
64 };
65 #endif
66
67 struct rte_table_hash {
68         struct rte_table_stats stats;
69
70         /* Input parameters */
71         uint32_t n_buckets;
72         uint32_t key_size;
73         uint32_t entry_size;
74         uint32_t bucket_size;
75         uint32_t key_offset;
76         uint64_t key_mask[2];
77         rte_table_hash_op_hash f_hash;
78         uint64_t seed;
79
80         /* Extendible buckets */
81         uint32_t n_buckets_ext;
82         uint32_t stack_pos;
83         uint32_t *stack;
84
85         /* Lookup table */
86         uint8_t memory[0] __rte_cache_aligned;
87 };
88
89 static int
90 keycmp(void *a, void *b, void *b_mask)
91 {
92         uint64_t *a64 = a, *b64 = b, *b_mask64 = b_mask;
93
94         return (a64[0] != (b64[0] & b_mask64[0])) ||
95                 (a64[1] != (b64[1] & b_mask64[1]));
96 }
97
98 static void
99 keycpy(void *dst, void *src, void *src_mask)
100 {
101         uint64_t *dst64 = dst, *src64 = src, *src_mask64 = src_mask;
102
103         dst64[0] = src64[0] & src_mask64[0];
104         dst64[1] = src64[1] & src_mask64[1];
105 }
106
107 static int
108 check_params_create(struct rte_table_hash_params *params)
109 {
110         /* name */
111         if (params->name == NULL) {
112                 RTE_LOG(ERR, TABLE, "%s: name invalid value\n", __func__);
113                 return -EINVAL;
114         }
115
116         /* key_size */
117         if (params->key_size != KEY_SIZE) {
118                 RTE_LOG(ERR, TABLE, "%s: key_size invalid value\n", __func__);
119                 return -EINVAL;
120         }
121
122         /* n_keys */
123         if (params->n_keys == 0) {
124                 RTE_LOG(ERR, TABLE, "%s: n_keys is zero\n", __func__);
125                 return -EINVAL;
126         }
127
128         /* n_buckets */
129         if ((params->n_buckets == 0) ||
130                 (!rte_is_power_of_2(params->n_buckets))) {
131                 RTE_LOG(ERR, TABLE, "%s: n_buckets invalid value\n", __func__);
132                 return -EINVAL;
133         }
134
135         /* f_hash */
136         if (params->f_hash == NULL) {
137                 RTE_LOG(ERR, TABLE, "%s: f_hash function pointer is NULL\n",
138                         __func__);
139                 return -EINVAL;
140         }
141
142         return 0;
143 }
144
145 static void *
146 rte_table_hash_create_key16_lru(void *params,
147                 int socket_id,
148                 uint32_t entry_size)
149 {
150         struct rte_table_hash_params *p = params;
151         struct rte_table_hash *f;
152         uint64_t bucket_size, total_size;
153         uint32_t n_buckets, i;
154
155         /* Check input parameters */
156         if ((check_params_create(p) != 0) ||
157                 ((sizeof(struct rte_table_hash) % RTE_CACHE_LINE_SIZE) != 0) ||
158                 ((sizeof(struct rte_bucket_4_16) % 64) != 0))
159                 return NULL;
160
161         /*
162          * Table dimensioning
163          *
164          * Objective: Pick the number of buckets (n_buckets) so that there a chance
165          * to store n_keys keys in the table.
166          *
167          * Note: Since the buckets do not get extended, it is not possible to
168          * guarantee that n_keys keys can be stored in the table at any time. In the
169          * worst case scenario when all the n_keys fall into the same bucket, only
170          * a maximum of KEYS_PER_BUCKET keys will be stored in the table. This case
171          * defeats the purpose of the hash table. It indicates unsuitable f_hash or
172          * n_keys to n_buckets ratio.
173          *
174          * MIN(n_buckets) = (n_keys + KEYS_PER_BUCKET - 1) / KEYS_PER_BUCKET
175          */
176         n_buckets = rte_align32pow2(
177                 (p->n_keys + KEYS_PER_BUCKET - 1) / KEYS_PER_BUCKET);
178         n_buckets = RTE_MAX(n_buckets, p->n_buckets);
179
180         /* Memory allocation */
181         bucket_size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct rte_bucket_4_16) +
182                 KEYS_PER_BUCKET * entry_size);
183         total_size = sizeof(struct rte_table_hash) + n_buckets * bucket_size;
184
185         if (total_size > SIZE_MAX) {
186                 RTE_LOG(ERR, TABLE, "%s: Cannot allocate %" PRIu64 " bytes "
187                 "for hash table %s\n",
188                 __func__, total_size, p->name);
189                 return NULL;
190         }
191
192         f = rte_zmalloc_socket(p->name,
193                 (size_t)total_size,
194                 RTE_CACHE_LINE_SIZE,
195                 socket_id);
196         if (f == NULL) {
197                 RTE_LOG(ERR, TABLE, "%s: Cannot allocate %" PRIu64 " bytes "
198                 "for hash table %s\n",
199                 __func__, total_size, p->name);
200                 return NULL;
201         }
202         RTE_LOG(INFO, TABLE, "%s: Hash table %s memory footprint "
203                 "is %" PRIu64 " bytes\n",
204                 __func__, p->name, total_size);
205
206         /* Memory initialization */
207         f->n_buckets = n_buckets;
208         f->key_size = KEY_SIZE;
209         f->entry_size = entry_size;
210         f->bucket_size = bucket_size;
211         f->key_offset = p->key_offset;
212         f->f_hash = p->f_hash;
213         f->seed = p->seed;
214
215         if (p->key_mask != NULL) {
216                 f->key_mask[0] = ((uint64_t *)p->key_mask)[0];
217                 f->key_mask[1] = ((uint64_t *)p->key_mask)[1];
218         } else {
219                 f->key_mask[0] = 0xFFFFFFFFFFFFFFFFLLU;
220                 f->key_mask[1] = 0xFFFFFFFFFFFFFFFFLLU;
221         }
222
223         for (i = 0; i < n_buckets; i++) {
224                 struct rte_bucket_4_16 *bucket;
225
226                 bucket = (struct rte_bucket_4_16 *) &f->memory[i *
227                         f->bucket_size];
228                 lru_init(bucket);
229         }
230
231         return f;
232 }
233
234 static int
235 rte_table_hash_free_key16_lru(void *table)
236 {
237         struct rte_table_hash *f = table;
238
239         /* Check input parameters */
240         if (f == NULL) {
241                 RTE_LOG(ERR, TABLE, "%s: table parameter is NULL\n", __func__);
242                 return -EINVAL;
243         }
244
245         rte_free(f);
246         return 0;
247 }
248
249 static int
250 rte_table_hash_entry_add_key16_lru(
251         void *table,
252         void *key,
253         void *entry,
254         int *key_found,
255         void **entry_ptr)
256 {
257         struct rte_table_hash *f = table;
258         struct rte_bucket_4_16 *bucket;
259         uint64_t signature, pos;
260         uint32_t bucket_index, i;
261
262         signature = f->f_hash(key, f->key_mask, f->key_size, f->seed);
263         bucket_index = signature & (f->n_buckets - 1);
264         bucket = (struct rte_bucket_4_16 *)
265                 &f->memory[bucket_index * f->bucket_size];
266         signature |= RTE_BUCKET_ENTRY_VALID;
267
268         /* Key is present in the bucket */
269         for (i = 0; i < 4; i++) {
270                 uint64_t bucket_signature = bucket->signature[i];
271                 uint8_t *bucket_key = (uint8_t *) &bucket->key[i];
272
273                 if ((bucket_signature == signature) &&
274                         (keycmp(bucket_key, key, f->key_mask) == 0)) {
275                         uint8_t *bucket_data = &bucket->data[i * f->entry_size];
276
277                         memcpy(bucket_data, entry, f->entry_size);
278                         lru_update(bucket, i);
279                         *key_found = 1;
280                         *entry_ptr = (void *) bucket_data;
281                         return 0;
282                 }
283         }
284
285         /* Key is not present in the bucket */
286         for (i = 0; i < 4; i++) {
287                 uint64_t bucket_signature = bucket->signature[i];
288                 uint8_t *bucket_key = (uint8_t *) &bucket->key[i];
289
290                 if (bucket_signature == 0) {
291                         uint8_t *bucket_data = &bucket->data[i * f->entry_size];
292
293                         bucket->signature[i] = signature;
294                         keycpy(bucket_key, key, f->key_mask);
295                         memcpy(bucket_data, entry, f->entry_size);
296                         lru_update(bucket, i);
297                         *key_found = 0;
298                         *entry_ptr = (void *) bucket_data;
299
300                         return 0;
301                 }
302         }
303
304         /* Bucket full: replace LRU entry */
305         pos = lru_pos(bucket);
306         bucket->signature[pos] = signature;
307         keycpy(&bucket->key[pos], key, f->key_mask);
308         memcpy(&bucket->data[pos * f->entry_size], entry, f->entry_size);
309         lru_update(bucket, pos);
310         *key_found = 0;
311         *entry_ptr = (void *) &bucket->data[pos * f->entry_size];
312
313         return 0;
314 }
315
316 static int
317 rte_table_hash_entry_delete_key16_lru(
318         void *table,
319         void *key,
320         int *key_found,
321         void *entry)
322 {
323         struct rte_table_hash *f = table;
324         struct rte_bucket_4_16 *bucket;
325         uint64_t signature;
326         uint32_t bucket_index, i;
327
328         signature = f->f_hash(key, f->key_mask, f->key_size, f->seed);
329         bucket_index = signature & (f->n_buckets - 1);
330         bucket = (struct rte_bucket_4_16 *)
331                 &f->memory[bucket_index * f->bucket_size];
332         signature |= RTE_BUCKET_ENTRY_VALID;
333
334         /* Key is present in the bucket */
335         for (i = 0; i < 4; i++) {
336                 uint64_t bucket_signature = bucket->signature[i];
337                 uint8_t *bucket_key = (uint8_t *) &bucket->key[i];
338
339                 if ((bucket_signature == signature) &&
340                         (keycmp(bucket_key, key, f->key_mask) == 0)) {
341                         uint8_t *bucket_data = &bucket->data[i * f->entry_size];
342
343                         bucket->signature[i] = 0;
344                         *key_found = 1;
345                         if (entry)
346                                 memcpy(entry, bucket_data, f->entry_size);
347                         return 0;
348                 }
349         }
350
351         /* Key is not present in the bucket */
352         *key_found = 0;
353         return 0;
354 }
355
356 static void *
357 rte_table_hash_create_key16_ext(void *params,
358                 int socket_id,
359                 uint32_t entry_size)
360 {
361         struct rte_table_hash_params *p = params;
362         struct rte_table_hash *f;
363         uint64_t bucket_size, stack_size, total_size;
364         uint32_t n_buckets_ext, i;
365
366         /* Check input parameters */
367         if ((check_params_create(p) != 0) ||
368                 ((sizeof(struct rte_table_hash) % RTE_CACHE_LINE_SIZE) != 0) ||
369                 ((sizeof(struct rte_bucket_4_16) % 64) != 0))
370                 return NULL;
371
372         /*
373          * Table dimensioning
374          *
375          * Objective: Pick the number of bucket extensions (n_buckets_ext) so that
376          * it is guaranteed that n_keys keys can be stored in the table at any time.
377          *
378          * The worst case scenario takes place when all the n_keys keys fall into
379          * the same bucket. Actually, due to the KEYS_PER_BUCKET scheme, the worst
380          * case takes place when (n_keys - KEYS_PER_BUCKET + 1) keys fall into the
381          * same bucket, while the remaining (KEYS_PER_BUCKET - 1) keys each fall
382          * into a different bucket. This case defeats the purpose of the hash table.
383          * It indicates unsuitable f_hash or n_keys to n_buckets ratio.
384          *
385          * n_buckets_ext = n_keys / KEYS_PER_BUCKET + KEYS_PER_BUCKET - 1
386          */
387         n_buckets_ext = p->n_keys / KEYS_PER_BUCKET + KEYS_PER_BUCKET - 1;
388
389         /* Memory allocation */
390         bucket_size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct rte_bucket_4_16) +
391                 KEYS_PER_BUCKET * entry_size);
392         stack_size = RTE_CACHE_LINE_ROUNDUP(n_buckets_ext * sizeof(uint32_t));
393         total_size = sizeof(struct rte_table_hash) +
394                 (p->n_buckets + n_buckets_ext) * bucket_size + stack_size;
395         if (total_size > SIZE_MAX) {
396                 RTE_LOG(ERR, TABLE, "%s: Cannot allocate %" PRIu64 " bytes "
397                         "for hash table %s\n",
398                         __func__, total_size, p->name);
399                 return NULL;
400         }
401
402         f = rte_zmalloc_socket(p->name,
403                 (size_t)total_size,
404                 RTE_CACHE_LINE_SIZE,
405                 socket_id);
406         if (f == NULL) {
407                 RTE_LOG(ERR, TABLE, "%s: Cannot allocate %" PRIu64 " bytes "
408                         "for hash table %s\n",
409                         __func__, total_size, p->name);
410                 return NULL;
411         }
412         RTE_LOG(INFO, TABLE, "%s: Hash table %s memory footprint "
413                 "is %" PRIu64 " bytes\n",
414                 __func__, p->name, total_size);
415
416         /* Memory initialization */
417         f->n_buckets = p->n_buckets;
418         f->key_size = KEY_SIZE;
419         f->entry_size = entry_size;
420         f->bucket_size = bucket_size;
421         f->key_offset = p->key_offset;
422         f->f_hash = p->f_hash;
423         f->seed = p->seed;
424
425         f->n_buckets_ext = n_buckets_ext;
426         f->stack_pos = n_buckets_ext;
427         f->stack = (uint32_t *)
428                 &f->memory[(p->n_buckets + n_buckets_ext) * f->bucket_size];
429
430         if (p->key_mask != NULL) {
431                 f->key_mask[0] = (((uint64_t *)p->key_mask)[0]);
432                 f->key_mask[1] = (((uint64_t *)p->key_mask)[1]);
433         } else {
434                 f->key_mask[0] = 0xFFFFFFFFFFFFFFFFLLU;
435                 f->key_mask[1] = 0xFFFFFFFFFFFFFFFFLLU;
436         }
437
438         for (i = 0; i < n_buckets_ext; i++)
439                 f->stack[i] = i;
440
441         return f;
442 }
443
444 static int
445 rte_table_hash_free_key16_ext(void *table)
446 {
447         struct rte_table_hash *f = table;
448
449         /* Check input parameters */
450         if (f == NULL) {
451                 RTE_LOG(ERR, TABLE, "%s: table parameter is NULL\n", __func__);
452                 return -EINVAL;
453         }
454
455         rte_free(f);
456         return 0;
457 }
458
459 static int
460 rte_table_hash_entry_add_key16_ext(
461         void *table,
462         void *key,
463         void *entry,
464         int *key_found,
465         void **entry_ptr)
466 {
467         struct rte_table_hash *f = table;
468         struct rte_bucket_4_16 *bucket0, *bucket, *bucket_prev;
469         uint64_t signature;
470         uint32_t bucket_index, i;
471
472         signature = f->f_hash(key, f->key_mask, f->key_size, f->seed);
473         bucket_index = signature & (f->n_buckets - 1);
474         bucket0 = (struct rte_bucket_4_16 *)
475                 &f->memory[bucket_index * f->bucket_size];
476         signature |= RTE_BUCKET_ENTRY_VALID;
477
478         /* Key is present in the bucket */
479         for (bucket = bucket0; bucket != NULL; bucket = bucket->next)
480                 for (i = 0; i < 4; i++) {
481                         uint64_t bucket_signature = bucket->signature[i];
482                         uint8_t *bucket_key = (uint8_t *) &bucket->key[i];
483
484                         if ((bucket_signature == signature) &&
485                                 (keycmp(bucket_key, key, f->key_mask) == 0)) {
486                                 uint8_t *bucket_data = &bucket->data[i *
487                                         f->entry_size];
488
489                                 memcpy(bucket_data, entry, f->entry_size);
490                                 *key_found = 1;
491                                 *entry_ptr = (void *) bucket_data;
492                                 return 0;
493                         }
494                 }
495
496         /* Key is not present in the bucket */
497         for (bucket_prev = NULL, bucket = bucket0; bucket != NULL;
498                 bucket_prev = bucket, bucket = bucket->next)
499                 for (i = 0; i < 4; i++) {
500                         uint64_t bucket_signature = bucket->signature[i];
501                         uint8_t *bucket_key = (uint8_t *) &bucket->key[i];
502
503                         if (bucket_signature == 0) {
504                                 uint8_t *bucket_data = &bucket->data[i *
505                                         f->entry_size];
506
507                                 bucket->signature[i] = signature;
508                                 keycpy(bucket_key, key, f->key_mask);
509                                 memcpy(bucket_data, entry, f->entry_size);
510                                 *key_found = 0;
511                                 *entry_ptr = (void *) bucket_data;
512
513                                 return 0;
514                         }
515                 }
516
517         /* Bucket full: extend bucket */
518         if (f->stack_pos > 0) {
519                 bucket_index = f->stack[--f->stack_pos];
520
521                 bucket = (struct rte_bucket_4_16 *) &f->memory[(f->n_buckets +
522                         bucket_index) * f->bucket_size];
523                 bucket_prev->next = bucket;
524                 bucket_prev->next_valid = 1;
525
526                 bucket->signature[0] = signature;
527                 keycpy(&bucket->key[0], key, f->key_mask);
528                 memcpy(&bucket->data[0], entry, f->entry_size);
529                 *key_found = 0;
530                 *entry_ptr = (void *) &bucket->data[0];
531                 return 0;
532         }
533
534         return -ENOSPC;
535 }
536
537 static int
538 rte_table_hash_entry_delete_key16_ext(
539         void *table,
540         void *key,
541         int *key_found,
542         void *entry)
543 {
544         struct rte_table_hash *f = table;
545         struct rte_bucket_4_16 *bucket0, *bucket, *bucket_prev;
546         uint64_t signature;
547         uint32_t bucket_index, i;
548
549         signature = f->f_hash(key, f->key_mask, f->key_size, f->seed);
550         bucket_index = signature & (f->n_buckets - 1);
551         bucket0 = (struct rte_bucket_4_16 *)
552                 &f->memory[bucket_index * f->bucket_size];
553         signature |= RTE_BUCKET_ENTRY_VALID;
554
555         /* Key is present in the bucket */
556         for (bucket_prev = NULL, bucket = bucket0; bucket != NULL;
557                 bucket_prev = bucket, bucket = bucket->next)
558                 for (i = 0; i < 4; i++) {
559                         uint64_t bucket_signature = bucket->signature[i];
560                         uint8_t *bucket_key = (uint8_t *) &bucket->key[i];
561
562                         if ((bucket_signature == signature) &&
563                                 (keycmp(bucket_key, key, f->key_mask) == 0)) {
564                                 uint8_t *bucket_data = &bucket->data[i *
565                                         f->entry_size];
566
567                                 bucket->signature[i] = 0;
568                                 *key_found = 1;
569                                 if (entry)
570                                         memcpy(entry, bucket_data, f->entry_size);
571
572                                 if ((bucket->signature[0] == 0) &&
573                                         (bucket->signature[1] == 0) &&
574                                         (bucket->signature[2] == 0) &&
575                                         (bucket->signature[3] == 0) &&
576                                         (bucket_prev != NULL)) {
577                                         bucket_prev->next = bucket->next;
578                                         bucket_prev->next_valid =
579                                                 bucket->next_valid;
580
581                                         memset(bucket, 0,
582                                                 sizeof(struct rte_bucket_4_16));
583                                         bucket_index = (((uint8_t *)bucket -
584                                                 (uint8_t *)f->memory)/f->bucket_size) - f->n_buckets;
585                                         f->stack[f->stack_pos++] = bucket_index;
586                                 }
587
588                                 return 0;
589                         }
590                 }
591
592         /* Key is not present in the bucket */
593         *key_found = 0;
594         return 0;
595 }
596
597 #define lookup_key16_cmp(key_in, bucket, pos, f)                        \
598 {                                                               \
599         uint64_t xor[4][2], or[4], signature[4], k[2];          \
600                                                                 \
601         k[0] = key_in[0] & f->key_mask[0];                              \
602         k[1] = key_in[1] & f->key_mask[1];                              \
603         signature[0] = (~bucket->signature[0]) & 1;             \
604         signature[1] = (~bucket->signature[1]) & 1;             \
605         signature[2] = (~bucket->signature[2]) & 1;             \
606         signature[3] = (~bucket->signature[3]) & 1;             \
607                                                                 \
608         xor[0][0] = k[0] ^ bucket->key[0][0];                   \
609         xor[0][1] = k[1] ^ bucket->key[0][1];                   \
610                                                                 \
611         xor[1][0] = k[0] ^ bucket->key[1][0];                   \
612         xor[1][1] = k[1] ^ bucket->key[1][1];                   \
613                                                                 \
614         xor[2][0] = k[0] ^ bucket->key[2][0];                   \
615         xor[2][1] = k[1] ^ bucket->key[2][1];                   \
616                                                                 \
617         xor[3][0] = k[0] ^ bucket->key[3][0];                   \
618         xor[3][1] = k[1] ^ bucket->key[3][1];                   \
619                                                                 \
620         or[0] = xor[0][0] | xor[0][1] | signature[0];           \
621         or[1] = xor[1][0] | xor[1][1] | signature[1];           \
622         or[2] = xor[2][0] | xor[2][1] | signature[2];           \
623         or[3] = xor[3][0] | xor[3][1] | signature[3];           \
624                                                                 \
625         pos = 4;                                                \
626         if (or[0] == 0)                                         \
627                 pos = 0;                                        \
628         if (or[1] == 0)                                         \
629                 pos = 1;                                        \
630         if (or[2] == 0)                                         \
631                 pos = 2;                                        \
632         if (or[3] == 0)                                         \
633                 pos = 3;                                        \
634 }
635
636 #define lookup1_stage0(pkt0_index, mbuf0, pkts, pkts_mask, f)   \
637 {                                                               \
638         uint64_t pkt_mask;                                      \
639         uint32_t key_offset = f->key_offset;\
640                                                                 \
641         pkt0_index = __builtin_ctzll(pkts_mask);                \
642         pkt_mask = 1LLU << pkt0_index;                          \
643         pkts_mask &= ~pkt_mask;                                 \
644                                                                 \
645         mbuf0 = pkts[pkt0_index];                               \
646         rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf0, key_offset));\
647 }
648
649 #define lookup1_stage1(mbuf1, bucket1, f)                       \
650 {                                                               \
651         uint64_t *key;                                          \
652         uint64_t signature = 0;                         \
653         uint32_t bucket_index;                          \
654                                                                 \
655         key = RTE_MBUF_METADATA_UINT64_PTR(mbuf1, f->key_offset);\
656         signature = f->f_hash(key, f->key_mask, KEY_SIZE, f->seed);     \
657                                                                 \
658         bucket_index = signature & (f->n_buckets - 1);          \
659         bucket1 = (struct rte_bucket_4_16 *)                    \
660                 &f->memory[bucket_index * f->bucket_size];      \
661         rte_prefetch0(bucket1);                                 \
662         rte_prefetch0((void *)(((uintptr_t) bucket1) + RTE_CACHE_LINE_SIZE));\
663 }
664
665 #define lookup1_stage2_lru(pkt2_index, mbuf2, bucket2,          \
666                 pkts_mask_out, entries, f)                      \
667 {                                                               \
668         void *a;                                                \
669         uint64_t pkt_mask;                                      \
670         uint64_t *key;                                          \
671         uint32_t pos;                                           \
672                                                                 \
673         key = RTE_MBUF_METADATA_UINT64_PTR(mbuf2, f->key_offset);\
674         lookup_key16_cmp(key, bucket2, pos, f);                 \
675                                                                 \
676         pkt_mask = (bucket2->signature[pos] & 1LLU) << pkt2_index;\
677         pkts_mask_out |= pkt_mask;                              \
678                                                                 \
679         a = (void *) &bucket2->data[pos * f->entry_size];       \
680         rte_prefetch0(a);                                       \
681         entries[pkt2_index] = a;                                \
682         lru_update(bucket2, pos);                               \
683 }
684
685 #define lookup1_stage2_ext(pkt2_index, mbuf2, bucket2, pkts_mask_out, entries, \
686         buckets_mask, buckets, keys, f)                         \
687 {                                                               \
688         struct rte_bucket_4_16 *bucket_next;                    \
689         void *a;                                                \
690         uint64_t pkt_mask, bucket_mask;                         \
691         uint64_t *key;                                          \
692         uint32_t pos;                                           \
693                                                                 \
694         key = RTE_MBUF_METADATA_UINT64_PTR(mbuf2, f->key_offset);\
695         lookup_key16_cmp(key, bucket2, pos, f);                 \
696                                                                 \
697         pkt_mask = (bucket2->signature[pos] & 1LLU) << pkt2_index;\
698         pkts_mask_out |= pkt_mask;                              \
699                                                                 \
700         a = (void *) &bucket2->data[pos * f->entry_size];       \
701         rte_prefetch0(a);                                       \
702         entries[pkt2_index] = a;                                \
703                                                                 \
704         bucket_mask = (~pkt_mask) & (bucket2->next_valid << pkt2_index);\
705         buckets_mask |= bucket_mask;                            \
706         bucket_next = bucket2->next;                            \
707         buckets[pkt2_index] = bucket_next;                      \
708         keys[pkt2_index] = key;                                 \
709 }
710
711 #define lookup_grinder(pkt_index, buckets, keys, pkts_mask_out, entries,\
712         buckets_mask, f)                                        \
713 {                                                               \
714         struct rte_bucket_4_16 *bucket, *bucket_next;           \
715         void *a;                                                \
716         uint64_t pkt_mask, bucket_mask;                         \
717         uint64_t *key;                                          \
718         uint32_t pos;                                           \
719                                                                 \
720         bucket = buckets[pkt_index];                            \
721         key = keys[pkt_index];                                  \
722         lookup_key16_cmp(key, bucket, pos, f);                  \
723                                                                 \
724         pkt_mask = (bucket->signature[pos] & 1LLU) << pkt_index;\
725         pkts_mask_out |= pkt_mask;                              \
726                                                                 \
727         a = (void *) &bucket->data[pos * f->entry_size];        \
728         rte_prefetch0(a);                                       \
729         entries[pkt_index] = a;                                 \
730                                                                 \
731         bucket_mask = (~pkt_mask) & (bucket->next_valid << pkt_index);\
732         buckets_mask |= bucket_mask;                            \
733         bucket_next = bucket->next;                             \
734         rte_prefetch0(bucket_next);                             \
735         rte_prefetch0((void *)(((uintptr_t) bucket_next) + RTE_CACHE_LINE_SIZE));\
736         buckets[pkt_index] = bucket_next;                       \
737         keys[pkt_index] = key;                                  \
738 }
739
740 #define lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01,\
741                 pkts, pkts_mask, f)                             \
742 {                                                               \
743         uint64_t pkt00_mask, pkt01_mask;                        \
744         uint32_t key_offset = f->key_offset;            \
745                                                                 \
746         pkt00_index = __builtin_ctzll(pkts_mask);               \
747         pkt00_mask = 1LLU << pkt00_index;                       \
748         pkts_mask &= ~pkt00_mask;                               \
749                                                                 \
750         mbuf00 = pkts[pkt00_index];                             \
751         rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf00, key_offset));\
752                                                                 \
753         pkt01_index = __builtin_ctzll(pkts_mask);               \
754         pkt01_mask = 1LLU << pkt01_index;                       \
755         pkts_mask &= ~pkt01_mask;                               \
756                                                                 \
757         mbuf01 = pkts[pkt01_index];                             \
758         rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf01, key_offset));\
759 }
760
761 #define lookup2_stage0_with_odd_support(pkt00_index, pkt01_index,\
762                 mbuf00, mbuf01, pkts, pkts_mask, f)             \
763 {                                                               \
764         uint64_t pkt00_mask, pkt01_mask;                        \
765         uint32_t key_offset = f->key_offset;            \
766                                                                 \
767         pkt00_index = __builtin_ctzll(pkts_mask);               \
768         pkt00_mask = 1LLU << pkt00_index;                       \
769         pkts_mask &= ~pkt00_mask;                               \
770                                                                 \
771         mbuf00 = pkts[pkt00_index];                             \
772         rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf00, key_offset)); \
773                                                                 \
774         pkt01_index = __builtin_ctzll(pkts_mask);               \
775         if (pkts_mask == 0)                                     \
776                 pkt01_index = pkt00_index;                      \
777         pkt01_mask = 1LLU << pkt01_index;                       \
778         pkts_mask &= ~pkt01_mask;                               \
779                                                                 \
780         mbuf01 = pkts[pkt01_index];                             \
781         rte_prefetch0(RTE_MBUF_METADATA_UINT8_PTR(mbuf01, key_offset)); \
782 }
783
784 #define lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f)   \
785 {                                                               \
786         uint64_t *key10, *key11;                                        \
787         uint64_t signature10, signature11;                      \
788         uint32_t bucket10_index, bucket11_index;        \
789                                                                 \
790         key10 = RTE_MBUF_METADATA_UINT64_PTR(mbuf10, f->key_offset);\
791         signature10 = f->f_hash(key10, f->key_mask,      KEY_SIZE, f->seed);\
792         bucket10_index = signature10 & (f->n_buckets - 1);      \
793         bucket10 = (struct rte_bucket_4_16 *)                           \
794                 &f->memory[bucket10_index * f->bucket_size];    \
795         rte_prefetch0(bucket10);                                \
796         rte_prefetch0((void *)(((uintptr_t) bucket10) + RTE_CACHE_LINE_SIZE));\
797                                                                 \
798         key11 = RTE_MBUF_METADATA_UINT64_PTR(mbuf11, f->key_offset);\
799         signature11 = f->f_hash(key11, f->key_mask,      KEY_SIZE, f->seed);\
800         bucket11_index = signature11 & (f->n_buckets - 1);      \
801         bucket11 = (struct rte_bucket_4_16 *)                   \
802                 &f->memory[bucket11_index * f->bucket_size];    \
803         rte_prefetch0(bucket11);                                \
804         rte_prefetch0((void *)(((uintptr_t) bucket11) + RTE_CACHE_LINE_SIZE));\
805 }
806
807 #define lookup2_stage2_lru(pkt20_index, pkt21_index, mbuf20, mbuf21,\
808                 bucket20, bucket21, pkts_mask_out, entries, f)  \
809 {                                                               \
810         void *a20, *a21;                                        \
811         uint64_t pkt20_mask, pkt21_mask;                        \
812         uint64_t *key20, *key21;                                \
813         uint32_t pos20, pos21;                                  \
814                                                                 \
815         key20 = RTE_MBUF_METADATA_UINT64_PTR(mbuf20, f->key_offset);\
816         key21 = RTE_MBUF_METADATA_UINT64_PTR(mbuf21, f->key_offset);\
817                                                                 \
818         lookup_key16_cmp(key20, bucket20, pos20, f);            \
819         lookup_key16_cmp(key21, bucket21, pos21, f);            \
820                                                                 \
821         pkt20_mask = (bucket20->signature[pos20] & 1LLU) << pkt20_index;\
822         pkt21_mask = (bucket21->signature[pos21] & 1LLU) << pkt21_index;\
823         pkts_mask_out |= pkt20_mask | pkt21_mask;                       \
824                                                                 \
825         a20 = (void *) &bucket20->data[pos20 * f->entry_size];  \
826         a21 = (void *) &bucket21->data[pos21 * f->entry_size];  \
827         rte_prefetch0(a20);                                     \
828         rte_prefetch0(a21);                                     \
829         entries[pkt20_index] = a20;                             \
830         entries[pkt21_index] = a21;                             \
831         lru_update(bucket20, pos20);                            \
832         lru_update(bucket21, pos21);                            \
833 }
834
835 #define lookup2_stage2_ext(pkt20_index, pkt21_index, mbuf20, mbuf21, bucket20, \
836         bucket21, pkts_mask_out, entries, buckets_mask, buckets, keys, f) \
837 {                                                               \
838         struct rte_bucket_4_16 *bucket20_next, *bucket21_next;  \
839         void *a20, *a21;                                        \
840         uint64_t pkt20_mask, pkt21_mask, bucket20_mask, bucket21_mask;\
841         uint64_t *key20, *key21;                                \
842         uint32_t pos20, pos21;                                  \
843                                                                 \
844         key20 = RTE_MBUF_METADATA_UINT64_PTR(mbuf20, f->key_offset);\
845         key21 = RTE_MBUF_METADATA_UINT64_PTR(mbuf21, f->key_offset);\
846                                                                 \
847         lookup_key16_cmp(key20, bucket20, pos20, f);    \
848         lookup_key16_cmp(key21, bucket21, pos21, f);    \
849                                                                 \
850         pkt20_mask = (bucket20->signature[pos20] & 1LLU) << pkt20_index;\
851         pkt21_mask = (bucket21->signature[pos21] & 1LLU) << pkt21_index;\
852         pkts_mask_out |= pkt20_mask | pkt21_mask;               \
853                                                                 \
854         a20 = (void *) &bucket20->data[pos20 * f->entry_size];  \
855         a21 = (void *) &bucket21->data[pos21 * f->entry_size];  \
856         rte_prefetch0(a20);                                     \
857         rte_prefetch0(a21);                                     \
858         entries[pkt20_index] = a20;                             \
859         entries[pkt21_index] = a21;                             \
860                                                                 \
861         bucket20_mask = (~pkt20_mask) & (bucket20->next_valid << pkt20_index);\
862         bucket21_mask = (~pkt21_mask) & (bucket21->next_valid << pkt21_index);\
863         buckets_mask |= bucket20_mask | bucket21_mask;          \
864         bucket20_next = bucket20->next;                         \
865         bucket21_next = bucket21->next;                         \
866         buckets[pkt20_index] = bucket20_next;                   \
867         buckets[pkt21_index] = bucket21_next;                   \
868         keys[pkt20_index] = key20;                              \
869         keys[pkt21_index] = key21;                              \
870 }
871
872 static int
873 rte_table_hash_lookup_key16_lru(
874         void *table,
875         struct rte_mbuf **pkts,
876         uint64_t pkts_mask,
877         uint64_t *lookup_hit_mask,
878         void **entries)
879 {
880         struct rte_table_hash *f = (struct rte_table_hash *) table;
881         struct rte_bucket_4_16 *bucket10, *bucket11, *bucket20, *bucket21;
882         struct rte_mbuf *mbuf00, *mbuf01, *mbuf10, *mbuf11, *mbuf20, *mbuf21;
883         uint32_t pkt00_index, pkt01_index, pkt10_index;
884         uint32_t pkt11_index, pkt20_index, pkt21_index;
885         uint64_t pkts_mask_out = 0;
886
887         __rte_unused uint32_t n_pkts_in = __builtin_popcountll(pkts_mask);
888
889         RTE_TABLE_HASH_KEY16_STATS_PKTS_IN_ADD(f, n_pkts_in);
890
891         /* Cannot run the pipeline with less than 5 packets */
892         if (__builtin_popcountll(pkts_mask) < 5) {
893                 for ( ; pkts_mask; ) {
894                         struct rte_bucket_4_16 *bucket;
895                         struct rte_mbuf *mbuf;
896                         uint32_t pkt_index;
897
898                         lookup1_stage0(pkt_index, mbuf, pkts, pkts_mask, f);
899                         lookup1_stage1(mbuf, bucket, f);
900                         lookup1_stage2_lru(pkt_index, mbuf, bucket,
901                                 pkts_mask_out, entries, f);
902                 }
903
904                 *lookup_hit_mask = pkts_mask_out;
905                 RTE_TABLE_HASH_KEY16_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in -
906                         __builtin_popcountll(pkts_mask_out));
907                 return 0;
908         }
909
910         /*
911          * Pipeline fill
912          *
913          */
914         /* Pipeline stage 0 */
915         lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
916                 pkts_mask, f);
917
918         /* Pipeline feed */
919         mbuf10 = mbuf00;
920         mbuf11 = mbuf01;
921         pkt10_index = pkt00_index;
922         pkt11_index = pkt01_index;
923
924         /* Pipeline stage 0 */
925         lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
926                 pkts_mask, f);
927
928         /* Pipeline stage 1 */
929         lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f);
930
931         /*
932          * Pipeline run
933          *
934          */
935         for ( ; pkts_mask; ) {
936                 /* Pipeline feed */
937                 bucket20 = bucket10;
938                 bucket21 = bucket11;
939                 mbuf20 = mbuf10;
940                 mbuf21 = mbuf11;
941                 mbuf10 = mbuf00;
942                 mbuf11 = mbuf01;
943                 pkt20_index = pkt10_index;
944                 pkt21_index = pkt11_index;
945                 pkt10_index = pkt00_index;
946                 pkt11_index = pkt01_index;
947
948                 /* Pipeline stage 0 */
949                 lookup2_stage0_with_odd_support(pkt00_index, pkt01_index,
950                         mbuf00, mbuf01, pkts, pkts_mask, f);
951
952                 /* Pipeline stage 1 */
953                 lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f);
954
955                 /* Pipeline stage 2 */
956                 lookup2_stage2_lru(pkt20_index, pkt21_index, mbuf20, mbuf21,
957                         bucket20, bucket21, pkts_mask_out, entries, f);
958         }
959
960         /*
961          * Pipeline flush
962          *
963          */
964         /* Pipeline feed */
965         bucket20 = bucket10;
966         bucket21 = bucket11;
967         mbuf20 = mbuf10;
968         mbuf21 = mbuf11;
969         mbuf10 = mbuf00;
970         mbuf11 = mbuf01;
971         pkt20_index = pkt10_index;
972         pkt21_index = pkt11_index;
973         pkt10_index = pkt00_index;
974         pkt11_index = pkt01_index;
975
976         /* Pipeline stage 1 */
977         lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f);
978
979         /* Pipeline stage 2 */
980         lookup2_stage2_lru(pkt20_index, pkt21_index, mbuf20, mbuf21,
981                 bucket20, bucket21, pkts_mask_out, entries, f);
982
983         /* Pipeline feed */
984         bucket20 = bucket10;
985         bucket21 = bucket11;
986         mbuf20 = mbuf10;
987         mbuf21 = mbuf11;
988         pkt20_index = pkt10_index;
989         pkt21_index = pkt11_index;
990
991         /* Pipeline stage 2 */
992         lookup2_stage2_lru(pkt20_index, pkt21_index, mbuf20, mbuf21,
993                 bucket20, bucket21, pkts_mask_out, entries, f);
994
995         *lookup_hit_mask = pkts_mask_out;
996         RTE_TABLE_HASH_KEY16_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in -
997                 __builtin_popcountll(pkts_mask_out));
998         return 0;
999 } /* lookup LRU */
1000
1001 static int
1002 rte_table_hash_lookup_key16_ext(
1003         void *table,
1004         struct rte_mbuf **pkts,
1005         uint64_t pkts_mask,
1006         uint64_t *lookup_hit_mask,
1007         void **entries)
1008 {
1009         struct rte_table_hash *f = (struct rte_table_hash *) table;
1010         struct rte_bucket_4_16 *bucket10, *bucket11, *bucket20, *bucket21;
1011         struct rte_mbuf *mbuf00, *mbuf01, *mbuf10, *mbuf11, *mbuf20, *mbuf21;
1012         uint32_t pkt00_index, pkt01_index, pkt10_index;
1013         uint32_t pkt11_index, pkt20_index, pkt21_index;
1014         uint64_t pkts_mask_out = 0, buckets_mask = 0;
1015         struct rte_bucket_4_16 *buckets[RTE_PORT_IN_BURST_SIZE_MAX];
1016         uint64_t *keys[RTE_PORT_IN_BURST_SIZE_MAX];
1017
1018         __rte_unused uint32_t n_pkts_in = __builtin_popcountll(pkts_mask);
1019
1020         RTE_TABLE_HASH_KEY16_STATS_PKTS_IN_ADD(f, n_pkts_in);
1021
1022         /* Cannot run the pipeline with less than 5 packets */
1023         if (__builtin_popcountll(pkts_mask) < 5) {
1024                 for ( ; pkts_mask; ) {
1025                         struct rte_bucket_4_16 *bucket;
1026                         struct rte_mbuf *mbuf;
1027                         uint32_t pkt_index;
1028
1029                         lookup1_stage0(pkt_index, mbuf, pkts, pkts_mask, f);
1030                         lookup1_stage1(mbuf, bucket, f);
1031                         lookup1_stage2_ext(pkt_index, mbuf, bucket,
1032                                 pkts_mask_out, entries, buckets_mask,
1033                                 buckets, keys, f);
1034                 }
1035
1036                 goto grind_next_buckets;
1037         }
1038
1039         /*
1040          * Pipeline fill
1041          *
1042          */
1043         /* Pipeline stage 0 */
1044         lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
1045                 pkts_mask, f);
1046
1047         /* Pipeline feed */
1048         mbuf10 = mbuf00;
1049         mbuf11 = mbuf01;
1050         pkt10_index = pkt00_index;
1051         pkt11_index = pkt01_index;
1052
1053         /* Pipeline stage 0 */
1054         lookup2_stage0(pkt00_index, pkt01_index, mbuf00, mbuf01, pkts,
1055                 pkts_mask, f);
1056
1057         /* Pipeline stage 1 */
1058         lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f);
1059
1060         /*
1061          * Pipeline run
1062          *
1063          */
1064         for ( ; pkts_mask; ) {
1065                 /* Pipeline feed */
1066                 bucket20 = bucket10;
1067                 bucket21 = bucket11;
1068                 mbuf20 = mbuf10;
1069                 mbuf21 = mbuf11;
1070                 mbuf10 = mbuf00;
1071                 mbuf11 = mbuf01;
1072                 pkt20_index = pkt10_index;
1073                 pkt21_index = pkt11_index;
1074                 pkt10_index = pkt00_index;
1075                 pkt11_index = pkt01_index;
1076
1077                 /* Pipeline stage 0 */
1078                 lookup2_stage0_with_odd_support(pkt00_index, pkt01_index,
1079                         mbuf00, mbuf01, pkts, pkts_mask, f);
1080
1081                 /* Pipeline stage 1 */
1082                 lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f);
1083
1084                 /* Pipeline stage 2 */
1085                 lookup2_stage2_ext(pkt20_index, pkt21_index, mbuf20, mbuf21,
1086                         bucket20, bucket21, pkts_mask_out, entries,
1087                         buckets_mask, buckets, keys, f);
1088         }
1089
1090         /*
1091          * Pipeline flush
1092          *
1093          */
1094         /* Pipeline feed */
1095         bucket20 = bucket10;
1096         bucket21 = bucket11;
1097         mbuf20 = mbuf10;
1098         mbuf21 = mbuf11;
1099         mbuf10 = mbuf00;
1100         mbuf11 = mbuf01;
1101         pkt20_index = pkt10_index;
1102         pkt21_index = pkt11_index;
1103         pkt10_index = pkt00_index;
1104         pkt11_index = pkt01_index;
1105
1106         /* Pipeline stage 1 */
1107         lookup2_stage1(mbuf10, mbuf11, bucket10, bucket11, f);
1108
1109         /* Pipeline stage 2 */
1110         lookup2_stage2_ext(pkt20_index, pkt21_index, mbuf20, mbuf21,
1111                 bucket20, bucket21, pkts_mask_out, entries,
1112                 buckets_mask, buckets, keys, f);
1113
1114         /* Pipeline feed */
1115         bucket20 = bucket10;
1116         bucket21 = bucket11;
1117         mbuf20 = mbuf10;
1118         mbuf21 = mbuf11;
1119         pkt20_index = pkt10_index;
1120         pkt21_index = pkt11_index;
1121
1122         /* Pipeline stage 2 */
1123         lookup2_stage2_ext(pkt20_index, pkt21_index, mbuf20, mbuf21,
1124                 bucket20, bucket21, pkts_mask_out, entries,
1125                 buckets_mask, buckets, keys, f);
1126
1127 grind_next_buckets:
1128         /* Grind next buckets */
1129         for ( ; buckets_mask; ) {
1130                 uint64_t buckets_mask_next = 0;
1131
1132                 for ( ; buckets_mask; ) {
1133                         uint64_t pkt_mask;
1134                         uint32_t pkt_index;
1135
1136                         pkt_index = __builtin_ctzll(buckets_mask);
1137                         pkt_mask = 1LLU << pkt_index;
1138                         buckets_mask &= ~pkt_mask;
1139
1140                         lookup_grinder(pkt_index, buckets, keys, pkts_mask_out,
1141                                 entries, buckets_mask_next, f);
1142                 }
1143
1144                 buckets_mask = buckets_mask_next;
1145         }
1146
1147         *lookup_hit_mask = pkts_mask_out;
1148         RTE_TABLE_HASH_KEY16_STATS_PKTS_LOOKUP_MISS(f, n_pkts_in -
1149                 __builtin_popcountll(pkts_mask_out));
1150         return 0;
1151 } /* lookup EXT */
1152
1153 static int
1154 rte_table_hash_key16_stats_read(void *table, struct rte_table_stats *stats, int clear)
1155 {
1156         struct rte_table_hash *t = table;
1157
1158         if (stats != NULL)
1159                 memcpy(stats, &t->stats, sizeof(t->stats));
1160
1161         if (clear)
1162                 memset(&t->stats, 0, sizeof(t->stats));
1163
1164         return 0;
1165 }
1166
1167 struct rte_table_ops rte_table_hash_key16_lru_ops = {
1168         .f_create = rte_table_hash_create_key16_lru,
1169         .f_free = rte_table_hash_free_key16_lru,
1170         .f_add = rte_table_hash_entry_add_key16_lru,
1171         .f_delete = rte_table_hash_entry_delete_key16_lru,
1172         .f_add_bulk = NULL,
1173         .f_delete_bulk = NULL,
1174         .f_lookup = rte_table_hash_lookup_key16_lru,
1175         .f_stats = rte_table_hash_key16_stats_read,
1176 };
1177
1178 struct rte_table_ops rte_table_hash_key16_ext_ops = {
1179         .f_create = rte_table_hash_create_key16_ext,
1180         .f_free = rte_table_hash_free_key16_ext,
1181         .f_add = rte_table_hash_entry_add_key16_ext,
1182         .f_delete = rte_table_hash_entry_delete_key16_ext,
1183         .f_add_bulk = NULL,
1184         .f_delete_bulk = NULL,
1185         .f_lookup = rte_table_hash_lookup_key16_ext,
1186         .f_stats = rte_table_hash_key16_stats_read,
1187 };