xref: /dpdk/lib/table/rte_swx_table_em.c (revision de0ec3c2458e3e2ce53e504c4ba92a36fcc78ef3)
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