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