199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson * Copyright(c) 2020 Intel Corporation
399a2dd95SBruce Richardson */
499a2dd95SBruce Richardson #include <string.h>
599a2dd95SBruce Richardson #include <stdio.h>
699a2dd95SBruce Richardson #include <errno.h>
799a2dd95SBruce Richardson
899a2dd95SBruce Richardson #include <rte_common.h>
999a2dd95SBruce Richardson #include <rte_prefetch.h>
1082ff0701SCristian Dumitrescu #include <rte_jhash.h>
1182ff0701SCristian Dumitrescu #include <rte_hash_crc.h>
1299a2dd95SBruce Richardson
1382ff0701SCristian Dumitrescu #include "rte_swx_keycmp.h"
1499a2dd95SBruce Richardson #include "rte_swx_table_em.h"
1599a2dd95SBruce Richardson
1699a2dd95SBruce Richardson #define CHECK(condition, err_code) \
1799a2dd95SBruce Richardson do { \
1899a2dd95SBruce Richardson if (!(condition)) \
1999a2dd95SBruce Richardson return -(err_code); \
2099a2dd95SBruce Richardson } while (0)
2199a2dd95SBruce Richardson
2299a2dd95SBruce Richardson #ifndef RTE_SWX_TABLE_EM_USE_HUGE_PAGES
2399a2dd95SBruce Richardson #define RTE_SWX_TABLE_EM_USE_HUGE_PAGES 1
2499a2dd95SBruce Richardson #endif
2599a2dd95SBruce Richardson
2699a2dd95SBruce Richardson #if RTE_SWX_TABLE_EM_USE_HUGE_PAGES
2799a2dd95SBruce Richardson
2899a2dd95SBruce Richardson #include <rte_malloc.h>
2999a2dd95SBruce Richardson
3099a2dd95SBruce Richardson static void *
env_malloc(size_t size,size_t alignment,int numa_node)3199a2dd95SBruce Richardson env_malloc(size_t size, size_t alignment, int numa_node)
3299a2dd95SBruce Richardson {
3399a2dd95SBruce Richardson return rte_zmalloc_socket(NULL, size, alignment, numa_node);
3499a2dd95SBruce Richardson }
3599a2dd95SBruce Richardson
3699a2dd95SBruce Richardson static void
env_free(void * start,size_t size __rte_unused)3799a2dd95SBruce Richardson env_free(void *start, size_t size __rte_unused)
3899a2dd95SBruce Richardson {
3999a2dd95SBruce Richardson rte_free(start);
4099a2dd95SBruce Richardson }
4199a2dd95SBruce Richardson
4299a2dd95SBruce Richardson #else
4399a2dd95SBruce Richardson
4499a2dd95SBruce Richardson #include <numa.h>
4599a2dd95SBruce Richardson
4699a2dd95SBruce Richardson static void *
env_malloc(size_t size,size_t alignment __rte_unused,int numa_node)4799a2dd95SBruce Richardson env_malloc(size_t size, size_t alignment __rte_unused, int numa_node)
4899a2dd95SBruce Richardson {
4999a2dd95SBruce Richardson return numa_alloc_onnode(size, numa_node);
5099a2dd95SBruce Richardson }
5199a2dd95SBruce Richardson
5299a2dd95SBruce Richardson static void
env_free(void * start,size_t size)5399a2dd95SBruce Richardson env_free(void *start, size_t size)
5499a2dd95SBruce Richardson {
5599a2dd95SBruce Richardson numa_free(start, size);
5699a2dd95SBruce Richardson }
5799a2dd95SBruce Richardson
5899a2dd95SBruce Richardson #endif
5999a2dd95SBruce Richardson
6099a2dd95SBruce Richardson static void
keycpy(void * dst,void * src,uint32_t n_bytes)6182ff0701SCristian Dumitrescu keycpy(void *dst, void *src, uint32_t n_bytes)
6299a2dd95SBruce Richardson {
6382ff0701SCristian Dumitrescu memcpy(dst, src, n_bytes);
6499a2dd95SBruce Richardson }
6599a2dd95SBruce Richardson
6699a2dd95SBruce Richardson #define KEYS_PER_BUCKET 4
6799a2dd95SBruce Richardson
6899a2dd95SBruce Richardson struct bucket_extension {
6999a2dd95SBruce Richardson struct bucket_extension *next;
7099a2dd95SBruce Richardson uint16_t sig[KEYS_PER_BUCKET];
7199a2dd95SBruce Richardson uint32_t key_id[KEYS_PER_BUCKET];
7299a2dd95SBruce Richardson };
7399a2dd95SBruce Richardson
7499a2dd95SBruce Richardson struct table {
7599a2dd95SBruce Richardson /* Input parameters */
7699a2dd95SBruce Richardson struct rte_swx_table_params params;
7799a2dd95SBruce Richardson
7899a2dd95SBruce Richardson /* Internal. */
7999a2dd95SBruce Richardson uint32_t key_size_shl;
8099a2dd95SBruce Richardson uint32_t data_size_shl;
8199a2dd95SBruce Richardson uint32_t n_buckets;
8299a2dd95SBruce Richardson uint32_t n_buckets_ext;
8399a2dd95SBruce Richardson uint32_t key_stack_tos;
8499a2dd95SBruce Richardson uint32_t bkt_ext_stack_tos;
8599a2dd95SBruce Richardson uint64_t total_size;
8682ff0701SCristian Dumitrescu rte_swx_keycmp_func_t keycmp_func;
8799a2dd95SBruce Richardson
8899a2dd95SBruce Richardson /* Memory arrays. */
8999a2dd95SBruce Richardson struct bucket_extension *buckets;
9099a2dd95SBruce Richardson struct bucket_extension *buckets_ext;
9199a2dd95SBruce Richardson uint8_t *keys;
9299a2dd95SBruce Richardson uint32_t *key_stack;
9399a2dd95SBruce Richardson uint32_t *bkt_ext_stack;
9499a2dd95SBruce Richardson uint8_t *data;
9599a2dd95SBruce Richardson };
9699a2dd95SBruce Richardson
9799a2dd95SBruce Richardson static inline uint8_t *
table_key(struct table * t,uint32_t key_id)9899a2dd95SBruce Richardson table_key(struct table *t, uint32_t key_id)
9999a2dd95SBruce Richardson {
10099a2dd95SBruce Richardson return &t->keys[(uint64_t)key_id << t->key_size_shl];
10199a2dd95SBruce Richardson }
10299a2dd95SBruce Richardson
10399a2dd95SBruce Richardson static inline uint64_t *
table_key_data(struct table * t,uint32_t key_id)10499a2dd95SBruce Richardson table_key_data(struct table *t, uint32_t key_id)
10599a2dd95SBruce Richardson {
10699a2dd95SBruce Richardson return (uint64_t *)&t->data[(uint64_t)key_id << t->data_size_shl];
10799a2dd95SBruce Richardson }
10899a2dd95SBruce Richardson
10999a2dd95SBruce Richardson static inline int
bkt_is_empty(struct bucket_extension * bkt)11099a2dd95SBruce Richardson bkt_is_empty(struct bucket_extension *bkt)
11199a2dd95SBruce Richardson {
11282ff0701SCristian Dumitrescu return (!bkt->sig[0] && !bkt->sig[1] && !bkt->sig[2] && !bkt->sig[3]) ? 1 : 0;
11399a2dd95SBruce Richardson }
11499a2dd95SBruce Richardson
11599a2dd95SBruce Richardson /* Return:
11699a2dd95SBruce Richardson * 0 = Bucket key position is NOT empty;
11799a2dd95SBruce Richardson * 1 = Bucket key position is empty.
11899a2dd95SBruce Richardson */
11999a2dd95SBruce Richardson static inline int
bkt_key_is_empty(struct bucket_extension * bkt,uint32_t bkt_pos)12099a2dd95SBruce Richardson bkt_key_is_empty(struct bucket_extension *bkt, uint32_t bkt_pos)
12199a2dd95SBruce Richardson {
12299a2dd95SBruce Richardson return bkt->sig[bkt_pos] ? 0 : 1;
12399a2dd95SBruce Richardson }
12499a2dd95SBruce Richardson
12599a2dd95SBruce Richardson /* Return: 0 = Keys are NOT equal; 1 = Keys are equal. */
12699a2dd95SBruce Richardson static inline int
bkt_keycmp(struct table * t,struct bucket_extension * bkt,uint8_t * input_key,uint32_t bkt_pos,uint32_t input_sig)12799a2dd95SBruce Richardson bkt_keycmp(struct table *t,
12899a2dd95SBruce Richardson struct bucket_extension *bkt,
12999a2dd95SBruce Richardson uint8_t *input_key,
13099a2dd95SBruce Richardson uint32_t bkt_pos,
13199a2dd95SBruce Richardson uint32_t input_sig)
13299a2dd95SBruce Richardson {
13399a2dd95SBruce Richardson uint32_t bkt_key_id;
13499a2dd95SBruce Richardson uint8_t *bkt_key;
13599a2dd95SBruce Richardson
13699a2dd95SBruce Richardson /* Key signature comparison. */
13799a2dd95SBruce Richardson if (input_sig != bkt->sig[bkt_pos])
13899a2dd95SBruce Richardson return 0;
13999a2dd95SBruce Richardson
14099a2dd95SBruce Richardson /* Key comparison. */
14199a2dd95SBruce Richardson bkt_key_id = bkt->key_id[bkt_pos];
14299a2dd95SBruce Richardson bkt_key = table_key(t, bkt_key_id);
14382ff0701SCristian Dumitrescu return t->keycmp_func(bkt_key, input_key, t->params.key_size);
14499a2dd95SBruce Richardson }
14599a2dd95SBruce Richardson
14699a2dd95SBruce Richardson static inline void
bkt_key_install(struct table * t,struct bucket_extension * bkt,struct rte_swx_table_entry * input,uint32_t bkt_pos,uint32_t bkt_key_id,uint32_t input_sig)14799a2dd95SBruce Richardson bkt_key_install(struct table *t,
14899a2dd95SBruce Richardson struct bucket_extension *bkt,
14999a2dd95SBruce Richardson struct rte_swx_table_entry *input,
15099a2dd95SBruce Richardson uint32_t bkt_pos,
15199a2dd95SBruce Richardson uint32_t bkt_key_id,
15299a2dd95SBruce Richardson uint32_t input_sig)
15399a2dd95SBruce Richardson {
15499a2dd95SBruce Richardson uint8_t *bkt_key;
15599a2dd95SBruce Richardson uint64_t *bkt_data;
15699a2dd95SBruce Richardson
15799a2dd95SBruce Richardson /* Key signature. */
15899a2dd95SBruce Richardson bkt->sig[bkt_pos] = (uint16_t)input_sig;
15999a2dd95SBruce Richardson
16099a2dd95SBruce Richardson /* Key. */
16199a2dd95SBruce Richardson bkt->key_id[bkt_pos] = bkt_key_id;
16299a2dd95SBruce Richardson bkt_key = table_key(t, bkt_key_id);
16382ff0701SCristian Dumitrescu keycpy(bkt_key, input->key, t->params.key_size);
16499a2dd95SBruce Richardson
16599a2dd95SBruce Richardson /* Key data. */
16699a2dd95SBruce Richardson bkt_data = table_key_data(t, bkt_key_id);
16799a2dd95SBruce Richardson bkt_data[0] = input->action_id;
16899a2dd95SBruce Richardson if (t->params.action_data_size && input->action_data)
16982ff0701SCristian Dumitrescu memcpy(&bkt_data[1], input->action_data, t->params.action_data_size);
17099a2dd95SBruce Richardson }
17199a2dd95SBruce Richardson
17299a2dd95SBruce Richardson static inline void
bkt_key_data_update(struct table * t,struct bucket_extension * bkt,struct rte_swx_table_entry * input,uint32_t bkt_pos)17399a2dd95SBruce Richardson bkt_key_data_update(struct table *t,
17499a2dd95SBruce Richardson struct bucket_extension *bkt,
17599a2dd95SBruce Richardson struct rte_swx_table_entry *input,
17699a2dd95SBruce Richardson uint32_t bkt_pos)
17799a2dd95SBruce Richardson {
17899a2dd95SBruce Richardson uint32_t bkt_key_id;
17999a2dd95SBruce Richardson uint64_t *bkt_data;
18099a2dd95SBruce Richardson
18199a2dd95SBruce Richardson /* Key. */
18299a2dd95SBruce Richardson bkt_key_id = bkt->key_id[bkt_pos];
18399a2dd95SBruce Richardson
18499a2dd95SBruce Richardson /* Key data. */
18599a2dd95SBruce Richardson bkt_data = table_key_data(t, bkt_key_id);
18699a2dd95SBruce Richardson bkt_data[0] = input->action_id;
18799a2dd95SBruce Richardson if (t->params.action_data_size && input->action_data)
18882ff0701SCristian Dumitrescu memcpy(&bkt_data[1], input->action_data, t->params.action_data_size);
18999a2dd95SBruce Richardson }
19099a2dd95SBruce Richardson
19199a2dd95SBruce Richardson #define CL RTE_CACHE_LINE_ROUNDUP
19299a2dd95SBruce Richardson
19399a2dd95SBruce Richardson static int
__table_create(struct table ** table,uint64_t * memory_footprint,struct rte_swx_table_params * params,const char * args __rte_unused,int numa_node)19499a2dd95SBruce Richardson __table_create(struct table **table,
19599a2dd95SBruce Richardson uint64_t *memory_footprint,
19699a2dd95SBruce Richardson struct rte_swx_table_params *params,
19799a2dd95SBruce Richardson const char *args __rte_unused,
19899a2dd95SBruce Richardson int numa_node)
19999a2dd95SBruce Richardson {
20099a2dd95SBruce Richardson struct table *t;
20199a2dd95SBruce Richardson uint8_t *memory;
20282ff0701SCristian Dumitrescu size_t table_meta_sz, bucket_sz, bucket_ext_sz, key_sz,
20399a2dd95SBruce Richardson key_stack_sz, bkt_ext_stack_sz, data_sz, total_size;
20482ff0701SCristian Dumitrescu size_t bucket_offset, bucket_ext_offset, key_offset,
20599a2dd95SBruce Richardson key_stack_offset, bkt_ext_stack_offset, data_offset;
20699a2dd95SBruce Richardson uint32_t key_size, key_data_size, n_buckets, n_buckets_ext, i;
20799a2dd95SBruce Richardson
20899a2dd95SBruce Richardson /* Check input arguments. */
20999a2dd95SBruce Richardson CHECK(params, EINVAL);
21099a2dd95SBruce Richardson CHECK(params->match_type == RTE_SWX_TABLE_MATCH_EXACT, EINVAL);
21199a2dd95SBruce Richardson CHECK(params->key_size, EINVAL);
21282ff0701SCristian Dumitrescu
21382ff0701SCristian Dumitrescu if (params->key_mask0) {
21482ff0701SCristian Dumitrescu for (i = 0; i < params->key_size; i++)
21582ff0701SCristian Dumitrescu if (params->key_mask0[i] != 0xFF)
21682ff0701SCristian Dumitrescu break;
21782ff0701SCristian Dumitrescu
21882ff0701SCristian Dumitrescu CHECK(i == params->key_size, EINVAL);
21982ff0701SCristian Dumitrescu }
22082ff0701SCristian Dumitrescu
22199a2dd95SBruce Richardson CHECK(params->n_keys_max, EINVAL);
22299a2dd95SBruce Richardson
22399a2dd95SBruce Richardson /* Memory allocation. */
22499a2dd95SBruce Richardson key_size = rte_align64pow2(params->key_size);
22599a2dd95SBruce Richardson key_data_size = rte_align64pow2(params->action_data_size + 8);
22682ff0701SCristian Dumitrescu n_buckets = rte_align64pow2((params->n_keys_max + KEYS_PER_BUCKET - 1) / KEYS_PER_BUCKET);
22782ff0701SCristian Dumitrescu n_buckets_ext = n_buckets;
22899a2dd95SBruce Richardson
22999a2dd95SBruce Richardson table_meta_sz = CL(sizeof(struct table));
23099a2dd95SBruce Richardson bucket_sz = CL(n_buckets * sizeof(struct bucket_extension));
23199a2dd95SBruce Richardson bucket_ext_sz = CL(n_buckets_ext * sizeof(struct bucket_extension));
23299a2dd95SBruce Richardson key_sz = CL(params->n_keys_max * key_size);
23399a2dd95SBruce Richardson key_stack_sz = CL(params->n_keys_max * sizeof(uint32_t));
23499a2dd95SBruce Richardson bkt_ext_stack_sz = CL(n_buckets_ext * sizeof(uint32_t));
23599a2dd95SBruce Richardson data_sz = CL(params->n_keys_max * key_data_size);
23682ff0701SCristian Dumitrescu total_size = table_meta_sz + bucket_sz + bucket_ext_sz +
23799a2dd95SBruce Richardson key_sz + key_stack_sz + bkt_ext_stack_sz + data_sz;
23899a2dd95SBruce Richardson
23982ff0701SCristian Dumitrescu bucket_offset = table_meta_sz;
24099a2dd95SBruce Richardson bucket_ext_offset = bucket_offset + bucket_sz;
24199a2dd95SBruce Richardson key_offset = bucket_ext_offset + bucket_ext_sz;
24299a2dd95SBruce Richardson key_stack_offset = key_offset + key_sz;
24399a2dd95SBruce Richardson bkt_ext_stack_offset = key_stack_offset + key_stack_sz;
24499a2dd95SBruce Richardson data_offset = bkt_ext_stack_offset + bkt_ext_stack_sz;
24599a2dd95SBruce Richardson
24699a2dd95SBruce Richardson if (!table) {
24799a2dd95SBruce Richardson if (memory_footprint)
24899a2dd95SBruce Richardson *memory_footprint = total_size;
24999a2dd95SBruce Richardson return 0;
25099a2dd95SBruce Richardson }
25199a2dd95SBruce Richardson
25299a2dd95SBruce Richardson memory = env_malloc(total_size, RTE_CACHE_LINE_SIZE, numa_node);
25399a2dd95SBruce Richardson CHECK(memory, ENOMEM);
25499a2dd95SBruce Richardson memset(memory, 0, total_size);
25599a2dd95SBruce Richardson
25699a2dd95SBruce Richardson /* Initialization. */
25799a2dd95SBruce Richardson t = (struct table *)memory;
25899a2dd95SBruce Richardson memcpy(&t->params, params, sizeof(*params));
25982ff0701SCristian Dumitrescu t->params.key_mask0 = NULL;
26082ff0701SCristian Dumitrescu if (!params->hash_func)
26182ff0701SCristian Dumitrescu t->params.hash_func = rte_hash_crc;
26299a2dd95SBruce Richardson
263*de0ec3c2STyler Retzlaff t->key_size_shl = rte_ctz32(key_size);
264*de0ec3c2STyler Retzlaff t->data_size_shl = rte_ctz32(key_data_size);
26599a2dd95SBruce Richardson t->n_buckets = n_buckets;
26699a2dd95SBruce Richardson t->n_buckets_ext = n_buckets_ext;
26799a2dd95SBruce Richardson t->total_size = total_size;
26882ff0701SCristian Dumitrescu t->keycmp_func = rte_swx_keycmp_func_get(params->key_size);
26999a2dd95SBruce Richardson
27099a2dd95SBruce Richardson t->buckets = (struct bucket_extension *)&memory[bucket_offset];
27199a2dd95SBruce Richardson t->buckets_ext = (struct bucket_extension *)&memory[bucket_ext_offset];
27299a2dd95SBruce Richardson t->keys = &memory[key_offset];
27399a2dd95SBruce Richardson t->key_stack = (uint32_t *)&memory[key_stack_offset];
27499a2dd95SBruce Richardson t->bkt_ext_stack = (uint32_t *)&memory[bkt_ext_stack_offset];
27599a2dd95SBruce Richardson t->data = &memory[data_offset];
27699a2dd95SBruce Richardson
27799a2dd95SBruce Richardson for (i = 0; i < t->params.n_keys_max; i++)
27899a2dd95SBruce Richardson t->key_stack[i] = t->params.n_keys_max - 1 - i;
27999a2dd95SBruce Richardson t->key_stack_tos = t->params.n_keys_max;
28099a2dd95SBruce Richardson
28199a2dd95SBruce Richardson for (i = 0; i < n_buckets_ext; i++)
28299a2dd95SBruce Richardson t->bkt_ext_stack[i] = n_buckets_ext - 1 - i;
28399a2dd95SBruce Richardson t->bkt_ext_stack_tos = n_buckets_ext;
28499a2dd95SBruce Richardson
28599a2dd95SBruce Richardson *table = t;
28699a2dd95SBruce Richardson return 0;
28799a2dd95SBruce Richardson }
28899a2dd95SBruce Richardson
28999a2dd95SBruce Richardson static void
table_free(void * table)29099a2dd95SBruce Richardson table_free(void *table)
29199a2dd95SBruce Richardson {
29299a2dd95SBruce Richardson struct table *t = table;
29399a2dd95SBruce Richardson
29499a2dd95SBruce Richardson if (!t)
29599a2dd95SBruce Richardson return;
29699a2dd95SBruce Richardson
29799a2dd95SBruce Richardson env_free(t, t->total_size);
29899a2dd95SBruce Richardson }
29999a2dd95SBruce Richardson
30099a2dd95SBruce Richardson static int
table_add(void * table,struct rte_swx_table_entry * entry)30199a2dd95SBruce Richardson table_add(void *table, struct rte_swx_table_entry *entry)
30299a2dd95SBruce Richardson {
30399a2dd95SBruce Richardson struct table *t = table;
30499a2dd95SBruce Richardson struct bucket_extension *bkt0, *bkt, *bkt_prev;
30599a2dd95SBruce Richardson uint32_t input_sig, bkt_id, i;
30699a2dd95SBruce Richardson
30799a2dd95SBruce Richardson CHECK(t, EINVAL);
30899a2dd95SBruce Richardson CHECK(entry, EINVAL);
30999a2dd95SBruce Richardson CHECK(entry->key, EINVAL);
31099a2dd95SBruce Richardson
31182ff0701SCristian Dumitrescu input_sig = t->params.hash_func(entry->key, t->params.key_size, 0);
31299a2dd95SBruce Richardson bkt_id = input_sig & (t->n_buckets - 1);
31399a2dd95SBruce Richardson bkt0 = &t->buckets[bkt_id];
31499a2dd95SBruce Richardson input_sig = (input_sig >> 16) | 1;
31599a2dd95SBruce Richardson
31699a2dd95SBruce Richardson /* Key is present in the bucket. */
31799a2dd95SBruce Richardson for (bkt = bkt0; bkt; bkt = bkt->next)
31899a2dd95SBruce Richardson for (i = 0; i < KEYS_PER_BUCKET; i++)
31999a2dd95SBruce Richardson if (bkt_keycmp(t, bkt, entry->key, i, input_sig)) {
32099a2dd95SBruce Richardson bkt_key_data_update(t, bkt, entry, i);
32199a2dd95SBruce Richardson return 0;
32299a2dd95SBruce Richardson }
32399a2dd95SBruce Richardson
32499a2dd95SBruce Richardson /* Key is not present in the bucket. Bucket not full. */
32599a2dd95SBruce Richardson for (bkt = bkt0, bkt_prev = NULL; bkt; bkt_prev = bkt, bkt = bkt->next)
32699a2dd95SBruce Richardson for (i = 0; i < KEYS_PER_BUCKET; i++)
32799a2dd95SBruce Richardson if (bkt_key_is_empty(bkt, i)) {
32899a2dd95SBruce Richardson uint32_t new_bkt_key_id;
32999a2dd95SBruce Richardson
33099a2dd95SBruce Richardson /* Allocate new key & install. */
33199a2dd95SBruce Richardson CHECK(t->key_stack_tos, ENOSPC);
33282ff0701SCristian Dumitrescu new_bkt_key_id = t->key_stack[--t->key_stack_tos];
33382ff0701SCristian Dumitrescu bkt_key_install(t, bkt, entry, i, new_bkt_key_id, input_sig);
33499a2dd95SBruce Richardson return 0;
33599a2dd95SBruce Richardson }
33699a2dd95SBruce Richardson
33799a2dd95SBruce Richardson /* Bucket full: extend bucket. */
33899a2dd95SBruce Richardson if (t->bkt_ext_stack_tos && t->key_stack_tos) {
33999a2dd95SBruce Richardson struct bucket_extension *new_bkt;
34099a2dd95SBruce Richardson uint32_t new_bkt_id, new_bkt_key_id;
34199a2dd95SBruce Richardson
34299a2dd95SBruce Richardson /* Allocate new bucket extension & install. */
34399a2dd95SBruce Richardson new_bkt_id = t->bkt_ext_stack[--t->bkt_ext_stack_tos];
34499a2dd95SBruce Richardson new_bkt = &t->buckets_ext[new_bkt_id];
34599a2dd95SBruce Richardson memset(new_bkt, 0, sizeof(*new_bkt));
34699a2dd95SBruce Richardson bkt_prev->next = new_bkt;
34799a2dd95SBruce Richardson
34899a2dd95SBruce Richardson /* Allocate new key & install. */
34999a2dd95SBruce Richardson new_bkt_key_id = t->key_stack[--t->key_stack_tos];
35082ff0701SCristian Dumitrescu bkt_key_install(t, new_bkt, entry, 0, new_bkt_key_id, input_sig);
35199a2dd95SBruce Richardson return 0;
35299a2dd95SBruce Richardson }
35399a2dd95SBruce Richardson
35499a2dd95SBruce Richardson CHECK(0, ENOSPC);
35599a2dd95SBruce Richardson }
35699a2dd95SBruce Richardson
35799a2dd95SBruce Richardson static int
table_del(void * table,struct rte_swx_table_entry * entry)35899a2dd95SBruce Richardson table_del(void *table, struct rte_swx_table_entry *entry)
35999a2dd95SBruce Richardson {
36099a2dd95SBruce Richardson struct table *t = table;
36199a2dd95SBruce Richardson struct bucket_extension *bkt0, *bkt, *bkt_prev;
36299a2dd95SBruce Richardson uint32_t input_sig, bkt_id, i;
36399a2dd95SBruce Richardson
36499a2dd95SBruce Richardson CHECK(t, EINVAL);
36599a2dd95SBruce Richardson CHECK(entry, EINVAL);
36699a2dd95SBruce Richardson CHECK(entry->key, EINVAL);
36799a2dd95SBruce Richardson
36882ff0701SCristian Dumitrescu input_sig = t->params.hash_func(entry->key, t->params.key_size, 0);
36999a2dd95SBruce Richardson bkt_id = input_sig & (t->n_buckets - 1);
37099a2dd95SBruce Richardson bkt0 = &t->buckets[bkt_id];
37199a2dd95SBruce Richardson input_sig = (input_sig >> 16) | 1;
37299a2dd95SBruce Richardson
37399a2dd95SBruce Richardson /* Key is present in the bucket. */
37499a2dd95SBruce Richardson for (bkt = bkt0, bkt_prev = NULL; bkt; bkt_prev = bkt, bkt = bkt->next)
37599a2dd95SBruce Richardson for (i = 0; i < KEYS_PER_BUCKET; i++)
37699a2dd95SBruce Richardson if (bkt_keycmp(t, bkt, entry->key, i, input_sig)) {
37799a2dd95SBruce Richardson /* Key free. */
37899a2dd95SBruce Richardson bkt->sig[i] = 0;
37982ff0701SCristian Dumitrescu t->key_stack[t->key_stack_tos++] = bkt->key_id[i];
38099a2dd95SBruce Richardson
38182ff0701SCristian Dumitrescu /* Bucket extension free if empty and not the 1st in bucket. */
38299a2dd95SBruce Richardson if (bkt_prev && bkt_is_empty(bkt)) {
38399a2dd95SBruce Richardson bkt_prev->next = bkt->next;
38499a2dd95SBruce Richardson bkt_id = bkt - t->buckets_ext;
38582ff0701SCristian Dumitrescu t->bkt_ext_stack[t->bkt_ext_stack_tos++] = bkt_id;
38699a2dd95SBruce Richardson }
38799a2dd95SBruce Richardson
38899a2dd95SBruce Richardson return 0;
38999a2dd95SBruce Richardson }
39099a2dd95SBruce Richardson
39199a2dd95SBruce Richardson return 0;
39299a2dd95SBruce Richardson }
39399a2dd95SBruce Richardson
39499a2dd95SBruce Richardson static uint64_t
table_mailbox_size_get_unoptimized(void)39599a2dd95SBruce Richardson table_mailbox_size_get_unoptimized(void)
39699a2dd95SBruce Richardson {
39799a2dd95SBruce Richardson return 0;
39899a2dd95SBruce Richardson }
39999a2dd95SBruce Richardson
40099a2dd95SBruce Richardson static int
table_lookup_unoptimized(void * table,void * mailbox __rte_unused,uint8_t ** key,uint64_t * action_id,uint8_t ** action_data,size_t * entry_id,int * hit)40199a2dd95SBruce Richardson table_lookup_unoptimized(void *table,
40299a2dd95SBruce Richardson void *mailbox __rte_unused,
40399a2dd95SBruce Richardson uint8_t **key,
40499a2dd95SBruce Richardson uint64_t *action_id,
40599a2dd95SBruce Richardson uint8_t **action_data,
40642605e56SCristian Dumitrescu size_t *entry_id,
40799a2dd95SBruce Richardson int *hit)
40899a2dd95SBruce Richardson {
40999a2dd95SBruce Richardson struct table *t = table;
41099a2dd95SBruce Richardson struct bucket_extension *bkt0, *bkt;
41199a2dd95SBruce Richardson uint8_t *input_key;
41299a2dd95SBruce Richardson uint32_t input_sig, bkt_id, i;
41399a2dd95SBruce Richardson
41499a2dd95SBruce Richardson input_key = &(*key)[t->params.key_offset];
41599a2dd95SBruce Richardson
41682ff0701SCristian Dumitrescu input_sig = t->params.hash_func(input_key, t->params.key_size, 0);
41799a2dd95SBruce Richardson bkt_id = input_sig & (t->n_buckets - 1);
41899a2dd95SBruce Richardson bkt0 = &t->buckets[bkt_id];
41999a2dd95SBruce Richardson input_sig = (input_sig >> 16) | 1;
42099a2dd95SBruce Richardson
42199a2dd95SBruce Richardson /* Key is present in the bucket. */
42299a2dd95SBruce Richardson for (bkt = bkt0; bkt; bkt = bkt->next)
42399a2dd95SBruce Richardson for (i = 0; i < KEYS_PER_BUCKET; i++)
42499a2dd95SBruce Richardson if (bkt_keycmp(t, bkt, input_key, i, input_sig)) {
42599a2dd95SBruce Richardson uint32_t bkt_key_id;
42699a2dd95SBruce Richardson uint64_t *bkt_data;
42799a2dd95SBruce Richardson
42899a2dd95SBruce Richardson /* Key. */
42999a2dd95SBruce Richardson bkt_key_id = bkt->key_id[i];
43099a2dd95SBruce Richardson
43199a2dd95SBruce Richardson /* Key data. */
43299a2dd95SBruce Richardson bkt_data = table_key_data(t, bkt_key_id);
43399a2dd95SBruce Richardson *action_id = bkt_data[0];
43499a2dd95SBruce Richardson *action_data = (uint8_t *)&bkt_data[1];
43542605e56SCristian Dumitrescu *entry_id = bkt_key_id;
43699a2dd95SBruce Richardson *hit = 1;
43799a2dd95SBruce Richardson return 1;
43899a2dd95SBruce Richardson }
43999a2dd95SBruce Richardson
44099a2dd95SBruce Richardson *hit = 0;
44199a2dd95SBruce Richardson return 1;
44299a2dd95SBruce Richardson }
44399a2dd95SBruce Richardson
44499a2dd95SBruce Richardson struct mailbox {
44599a2dd95SBruce Richardson struct bucket_extension *bkt;
44699a2dd95SBruce Richardson uint32_t input_sig;
44799a2dd95SBruce Richardson uint32_t bkt_key_id;
44899a2dd95SBruce Richardson uint32_t sig_match;
44999a2dd95SBruce Richardson uint32_t sig_match_many;
45099a2dd95SBruce Richardson int state;
45199a2dd95SBruce Richardson };
45299a2dd95SBruce Richardson
45399a2dd95SBruce Richardson static uint64_t
table_mailbox_size_get(void)45499a2dd95SBruce Richardson table_mailbox_size_get(void)
45599a2dd95SBruce Richardson {
45699a2dd95SBruce Richardson return sizeof(struct mailbox);
45799a2dd95SBruce Richardson }
45899a2dd95SBruce Richardson
45999a2dd95SBruce Richardson /*
46099a2dd95SBruce Richardson * mask = match bitmask
46199a2dd95SBruce Richardson * match = at least one match
46299a2dd95SBruce Richardson * match_many = more than one match
46399a2dd95SBruce Richardson * match_pos = position of first match
46499a2dd95SBruce Richardson *
46599a2dd95SBruce Richardson *+------+-------+------------+-----------+
46699a2dd95SBruce Richardson *| mask | match | match_many | match_pos |
46799a2dd95SBruce Richardson *+------+-------+------------+-----------+
46899a2dd95SBruce Richardson *| 0000 | 0 | 0 | 00 |
46999a2dd95SBruce Richardson *| 0001 | 1 | 0 | 00 |
47099a2dd95SBruce Richardson *| 0010 | 1 | 0 | 01 |
47199a2dd95SBruce Richardson *| 0011 | 1 | 1 | 00 |
47299a2dd95SBruce Richardson *+------+-------+------------+-----------+
47399a2dd95SBruce Richardson *| 0100 | 1 | 0 | 10 |
47499a2dd95SBruce Richardson *| 0101 | 1 | 1 | 00 |
47599a2dd95SBruce Richardson *| 0110 | 1 | 1 | 01 |
47699a2dd95SBruce Richardson *| 0111 | 1 | 1 | 00 |
47799a2dd95SBruce Richardson *+------+-------+------------+-----------+
47899a2dd95SBruce Richardson *| 1000 | 1 | 0 | 11 |
47999a2dd95SBruce Richardson *| 1001 | 1 | 1 | 00 |
48099a2dd95SBruce Richardson *| 1010 | 1 | 1 | 01 |
48199a2dd95SBruce Richardson *| 1011 | 1 | 1 | 00 |
48299a2dd95SBruce Richardson *+------+-------+------------+-----------+
48399a2dd95SBruce Richardson *| 1100 | 1 | 1 | 10 |
48499a2dd95SBruce Richardson *| 1101 | 1 | 1 | 00 |
48599a2dd95SBruce Richardson *| 1110 | 1 | 1 | 01 |
48699a2dd95SBruce Richardson *| 1111 | 1 | 1 | 00 |
48799a2dd95SBruce Richardson *+------+-------+------------+-----------+
48899a2dd95SBruce Richardson *
48999a2dd95SBruce Richardson * match = 1111_1111_1111_1110 = 0xFFFE
49099a2dd95SBruce Richardson * match_many = 1111_1110_1110_1000 = 0xFEE8
49199a2dd95SBruce Richardson * match_pos = 0001_0010_0001_0011__0001_0010_0001_0000 = 0x12131210
49299a2dd95SBruce Richardson */
49399a2dd95SBruce Richardson
49499a2dd95SBruce Richardson #define LUT_MATCH 0xFFFE
49599a2dd95SBruce Richardson #define LUT_MATCH_MANY 0xFEE8
49699a2dd95SBruce Richardson #define LUT_MATCH_POS 0x12131210
49799a2dd95SBruce Richardson
49899a2dd95SBruce Richardson static int
table_lookup(void * table,void * mailbox,uint8_t ** key,uint64_t * action_id,uint8_t ** action_data,size_t * entry_id,int * hit)49999a2dd95SBruce Richardson table_lookup(void *table,
50099a2dd95SBruce Richardson void *mailbox,
50199a2dd95SBruce Richardson uint8_t **key,
50299a2dd95SBruce Richardson uint64_t *action_id,
50399a2dd95SBruce Richardson uint8_t **action_data,
50442605e56SCristian Dumitrescu size_t *entry_id,
50599a2dd95SBruce Richardson int *hit)
50699a2dd95SBruce Richardson {
50799a2dd95SBruce Richardson struct table *t = table;
50899a2dd95SBruce Richardson struct mailbox *m = mailbox;
50999a2dd95SBruce Richardson
51099a2dd95SBruce Richardson switch (m->state) {
51199a2dd95SBruce Richardson case 0: {
51299a2dd95SBruce Richardson uint8_t *input_key = &(*key)[t->params.key_offset];
51399a2dd95SBruce Richardson struct bucket_extension *bkt;
51499a2dd95SBruce Richardson uint32_t input_sig, bkt_id;
51599a2dd95SBruce Richardson
51682ff0701SCristian Dumitrescu input_sig = t->params.hash_func(input_key, t->params.key_size, 0);
51799a2dd95SBruce Richardson bkt_id = input_sig & (t->n_buckets - 1);
51899a2dd95SBruce Richardson bkt = &t->buckets[bkt_id];
51999a2dd95SBruce Richardson rte_prefetch0(bkt);
52099a2dd95SBruce Richardson
52199a2dd95SBruce Richardson m->bkt = bkt;
52299a2dd95SBruce Richardson m->input_sig = (input_sig >> 16) | 1;
52399a2dd95SBruce Richardson m->state++;
52499a2dd95SBruce Richardson return 0;
52599a2dd95SBruce Richardson }
52699a2dd95SBruce Richardson
52799a2dd95SBruce Richardson case 1: {
52899a2dd95SBruce Richardson struct bucket_extension *bkt = m->bkt;
52999a2dd95SBruce Richardson uint32_t input_sig = m->input_sig;
53099a2dd95SBruce Richardson uint32_t bkt_sig0, bkt_sig1, bkt_sig2, bkt_sig3;
53199a2dd95SBruce Richardson uint32_t mask0 = 0, mask1 = 0, mask2 = 0, mask3 = 0, mask_all;
53299a2dd95SBruce Richardson uint32_t sig_match = LUT_MATCH;
53399a2dd95SBruce Richardson uint32_t sig_match_many = LUT_MATCH_MANY;
53499a2dd95SBruce Richardson uint32_t sig_match_pos = LUT_MATCH_POS;
53599a2dd95SBruce Richardson uint32_t bkt_key_id;
53699a2dd95SBruce Richardson
53799a2dd95SBruce Richardson bkt_sig0 = input_sig ^ bkt->sig[0];
53899a2dd95SBruce Richardson if (!bkt_sig0)
53999a2dd95SBruce Richardson mask0 = 1 << 0;
54099a2dd95SBruce Richardson
54199a2dd95SBruce Richardson bkt_sig1 = input_sig ^ bkt->sig[1];
54299a2dd95SBruce Richardson if (!bkt_sig1)
54399a2dd95SBruce Richardson mask1 = 1 << 1;
54499a2dd95SBruce Richardson
54599a2dd95SBruce Richardson bkt_sig2 = input_sig ^ bkt->sig[2];
54699a2dd95SBruce Richardson if (!bkt_sig2)
54799a2dd95SBruce Richardson mask2 = 1 << 2;
54899a2dd95SBruce Richardson
54999a2dd95SBruce Richardson bkt_sig3 = input_sig ^ bkt->sig[3];
55099a2dd95SBruce Richardson if (!bkt_sig3)
55199a2dd95SBruce Richardson mask3 = 1 << 3;
55299a2dd95SBruce Richardson
55399a2dd95SBruce Richardson mask_all = (mask0 | mask1) | (mask2 | mask3);
55499a2dd95SBruce Richardson sig_match = (sig_match >> mask_all) & 1;
55599a2dd95SBruce Richardson sig_match_many = (sig_match_many >> mask_all) & 1;
55699a2dd95SBruce Richardson sig_match_pos = (sig_match_pos >> (mask_all << 1)) & 3;
55799a2dd95SBruce Richardson
55899a2dd95SBruce Richardson bkt_key_id = bkt->key_id[sig_match_pos];
55999a2dd95SBruce Richardson rte_prefetch0(table_key(t, bkt_key_id));
56099a2dd95SBruce Richardson rte_prefetch0(table_key_data(t, bkt_key_id));
56199a2dd95SBruce Richardson
56299a2dd95SBruce Richardson m->bkt_key_id = bkt_key_id;
56399a2dd95SBruce Richardson m->sig_match = sig_match;
56499a2dd95SBruce Richardson m->sig_match_many = sig_match_many;
56599a2dd95SBruce Richardson m->state++;
56699a2dd95SBruce Richardson return 0;
56799a2dd95SBruce Richardson }
56899a2dd95SBruce Richardson
56999a2dd95SBruce Richardson case 2: {
57099a2dd95SBruce Richardson uint8_t *input_key = &(*key)[t->params.key_offset];
57199a2dd95SBruce Richardson struct bucket_extension *bkt = m->bkt;
57299a2dd95SBruce Richardson uint32_t bkt_key_id = m->bkt_key_id;
57399a2dd95SBruce Richardson uint8_t *bkt_key = table_key(t, bkt_key_id);
57499a2dd95SBruce Richardson uint64_t *bkt_data = table_key_data(t, bkt_key_id);
57599a2dd95SBruce Richardson uint32_t lkp_hit;
57699a2dd95SBruce Richardson
57782ff0701SCristian Dumitrescu lkp_hit = t->keycmp_func(bkt_key, input_key, t->params.key_size);
57899a2dd95SBruce Richardson lkp_hit &= m->sig_match;
57999a2dd95SBruce Richardson *action_id = bkt_data[0];
58099a2dd95SBruce Richardson *action_data = (uint8_t *)&bkt_data[1];
58142605e56SCristian Dumitrescu *entry_id = bkt_key_id;
58299a2dd95SBruce Richardson *hit = lkp_hit;
58399a2dd95SBruce Richardson
58499a2dd95SBruce Richardson m->state = 0;
58599a2dd95SBruce Richardson
58699a2dd95SBruce Richardson if (!lkp_hit && (m->sig_match_many || bkt->next))
58799a2dd95SBruce Richardson return table_lookup_unoptimized(t,
58899a2dd95SBruce Richardson m,
58999a2dd95SBruce Richardson key,
59099a2dd95SBruce Richardson action_id,
59199a2dd95SBruce Richardson action_data,
59242605e56SCristian Dumitrescu entry_id,
59399a2dd95SBruce Richardson hit);
59499a2dd95SBruce Richardson
59599a2dd95SBruce Richardson return 1;
59699a2dd95SBruce Richardson }
59799a2dd95SBruce Richardson
59899a2dd95SBruce Richardson default:
59999a2dd95SBruce Richardson return 0;
60099a2dd95SBruce Richardson }
60199a2dd95SBruce Richardson }
60299a2dd95SBruce Richardson
60399a2dd95SBruce Richardson static void *
table_create(struct rte_swx_table_params * params,struct rte_swx_table_entry_list * entries,const char * args,int numa_node)60499a2dd95SBruce Richardson table_create(struct rte_swx_table_params *params,
60599a2dd95SBruce Richardson struct rte_swx_table_entry_list *entries,
60699a2dd95SBruce Richardson const char *args,
60799a2dd95SBruce Richardson int numa_node)
60899a2dd95SBruce Richardson {
60999a2dd95SBruce Richardson struct table *t;
61099a2dd95SBruce Richardson struct rte_swx_table_entry *entry;
61199a2dd95SBruce Richardson int status;
61299a2dd95SBruce Richardson
61399a2dd95SBruce Richardson /* Table create. */
61499a2dd95SBruce Richardson status = __table_create(&t, NULL, params, args, numa_node);
61599a2dd95SBruce Richardson if (status)
61699a2dd95SBruce Richardson return NULL;
61799a2dd95SBruce Richardson
61899a2dd95SBruce Richardson /* Table add entries. */
61999a2dd95SBruce Richardson if (!entries)
62099a2dd95SBruce Richardson return t;
62199a2dd95SBruce Richardson
62299a2dd95SBruce Richardson TAILQ_FOREACH(entry, entries, node) {
62399a2dd95SBruce Richardson int status;
62499a2dd95SBruce Richardson
62599a2dd95SBruce Richardson status = table_add(t, entry);
62699a2dd95SBruce Richardson if (status) {
62799a2dd95SBruce Richardson table_free(t);
62899a2dd95SBruce Richardson return NULL;
62999a2dd95SBruce Richardson }
63099a2dd95SBruce Richardson }
63199a2dd95SBruce Richardson
63299a2dd95SBruce Richardson return t;
63399a2dd95SBruce Richardson }
63499a2dd95SBruce Richardson
63599a2dd95SBruce Richardson static uint64_t
table_footprint(struct rte_swx_table_params * params,struct rte_swx_table_entry_list * entries __rte_unused,const char * args)63699a2dd95SBruce Richardson table_footprint(struct rte_swx_table_params *params,
63799a2dd95SBruce Richardson struct rte_swx_table_entry_list *entries __rte_unused,
63899a2dd95SBruce Richardson const char *args)
63999a2dd95SBruce Richardson {
64099a2dd95SBruce Richardson uint64_t memory_footprint;
64199a2dd95SBruce Richardson int status;
64299a2dd95SBruce Richardson
64399a2dd95SBruce Richardson status = __table_create(NULL, &memory_footprint, params, args, 0);
64499a2dd95SBruce Richardson if (status)
64599a2dd95SBruce Richardson return 0;
64699a2dd95SBruce Richardson
64799a2dd95SBruce Richardson return memory_footprint;
64899a2dd95SBruce Richardson }
64999a2dd95SBruce Richardson
65099a2dd95SBruce Richardson struct rte_swx_table_ops rte_swx_table_exact_match_unoptimized_ops = {
65199a2dd95SBruce Richardson .footprint_get = table_footprint,
65299a2dd95SBruce Richardson .mailbox_size_get = table_mailbox_size_get_unoptimized,
65399a2dd95SBruce Richardson .create = table_create,
65499a2dd95SBruce Richardson .add = table_add,
65599a2dd95SBruce Richardson .del = table_del,
65699a2dd95SBruce Richardson .lkp = table_lookup_unoptimized,
65799a2dd95SBruce Richardson .free = table_free,
65899a2dd95SBruce Richardson };
65999a2dd95SBruce Richardson
66099a2dd95SBruce Richardson struct rte_swx_table_ops rte_swx_table_exact_match_ops = {
66199a2dd95SBruce Richardson .footprint_get = table_footprint,
66299a2dd95SBruce Richardson .mailbox_size_get = table_mailbox_size_get,
66399a2dd95SBruce Richardson .create = table_create,
66499a2dd95SBruce Richardson .add = table_add,
66599a2dd95SBruce Richardson .del = table_del,
66699a2dd95SBruce Richardson .lkp = table_lookup,
66799a2dd95SBruce Richardson .free = table_free,
66899a2dd95SBruce Richardson };
669