10c06fa3bSCristian Dumitrescu /* SPDX-License-Identifier: BSD-3-Clause
20c06fa3bSCristian Dumitrescu * Copyright(c) 2020 Intel Corporation
30c06fa3bSCristian Dumitrescu */
40c06fa3bSCristian Dumitrescu #include <string.h>
50c06fa3bSCristian Dumitrescu #include <stdio.h>
60c06fa3bSCristian Dumitrescu #include <errno.h>
70c06fa3bSCristian Dumitrescu
80c06fa3bSCristian Dumitrescu #include <rte_common.h>
90c06fa3bSCristian Dumitrescu #include <rte_cycles.h>
100c06fa3bSCristian Dumitrescu #include <rte_prefetch.h>
110d871d7eSCristian Dumitrescu #include <rte_jhash.h>
120d871d7eSCristian Dumitrescu #include <rte_hash_crc.h>
130c06fa3bSCristian Dumitrescu
140d871d7eSCristian Dumitrescu #include "rte_swx_keycmp.h"
150c06fa3bSCristian Dumitrescu #include "rte_swx_table_learner.h"
160c06fa3bSCristian Dumitrescu
170c06fa3bSCristian Dumitrescu #ifndef RTE_SWX_TABLE_LEARNER_USE_HUGE_PAGES
180c06fa3bSCristian Dumitrescu #define RTE_SWX_TABLE_LEARNER_USE_HUGE_PAGES 1
190c06fa3bSCristian Dumitrescu #endif
200c06fa3bSCristian Dumitrescu
210c06fa3bSCristian Dumitrescu #ifndef RTE_SWX_TABLE_SELECTOR_HUGE_PAGES_DISABLE
220c06fa3bSCristian Dumitrescu
230c06fa3bSCristian Dumitrescu #include <rte_malloc.h>
240c06fa3bSCristian Dumitrescu
250c06fa3bSCristian Dumitrescu static void *
env_calloc(size_t size,size_t alignment,int numa_node)260c06fa3bSCristian Dumitrescu env_calloc(size_t size, size_t alignment, int numa_node)
270c06fa3bSCristian Dumitrescu {
280c06fa3bSCristian Dumitrescu return rte_zmalloc_socket(NULL, size, alignment, numa_node);
290c06fa3bSCristian Dumitrescu }
300c06fa3bSCristian Dumitrescu
310c06fa3bSCristian Dumitrescu static void
env_free(void * start,size_t size __rte_unused)320c06fa3bSCristian Dumitrescu env_free(void *start, size_t size __rte_unused)
330c06fa3bSCristian Dumitrescu {
340c06fa3bSCristian Dumitrescu rte_free(start);
350c06fa3bSCristian Dumitrescu }
360c06fa3bSCristian Dumitrescu
370c06fa3bSCristian Dumitrescu #else
380c06fa3bSCristian Dumitrescu
390c06fa3bSCristian Dumitrescu #include <numa.h>
400c06fa3bSCristian Dumitrescu
410c06fa3bSCristian Dumitrescu static void *
env_calloc(size_t size,size_t alignment __rte_unused,int numa_node)420c06fa3bSCristian Dumitrescu env_calloc(size_t size, size_t alignment __rte_unused, int numa_node)
430c06fa3bSCristian Dumitrescu {
440c06fa3bSCristian Dumitrescu void *start;
450c06fa3bSCristian Dumitrescu
460c06fa3bSCristian Dumitrescu if (numa_available() == -1)
470c06fa3bSCristian Dumitrescu return NULL;
480c06fa3bSCristian Dumitrescu
490c06fa3bSCristian Dumitrescu start = numa_alloc_onnode(size, numa_node);
500c06fa3bSCristian Dumitrescu if (!start)
510c06fa3bSCristian Dumitrescu return NULL;
520c06fa3bSCristian Dumitrescu
530c06fa3bSCristian Dumitrescu memset(start, 0, size);
540c06fa3bSCristian Dumitrescu return start;
550c06fa3bSCristian Dumitrescu }
560c06fa3bSCristian Dumitrescu
570c06fa3bSCristian Dumitrescu static void
env_free(void * start,size_t size)580c06fa3bSCristian Dumitrescu env_free(void *start, size_t size)
590c06fa3bSCristian Dumitrescu {
600c06fa3bSCristian Dumitrescu if ((numa_available() == -1) || !start)
610c06fa3bSCristian Dumitrescu return;
620c06fa3bSCristian Dumitrescu
630c06fa3bSCristian Dumitrescu numa_free(start, size);
640c06fa3bSCristian Dumitrescu }
650c06fa3bSCristian Dumitrescu
660c06fa3bSCristian Dumitrescu #endif
670c06fa3bSCristian Dumitrescu
688186c0bbSCristian Dumitrescu static void
table_keycpy(void * dst,void * src,uint32_t n_bytes)690d871d7eSCristian Dumitrescu table_keycpy(void *dst, void *src, uint32_t n_bytes)
708186c0bbSCristian Dumitrescu {
710d871d7eSCristian Dumitrescu memcpy(dst, src, n_bytes);
720c06fa3bSCristian Dumitrescu }
730c06fa3bSCristian Dumitrescu
740c06fa3bSCristian Dumitrescu #define TABLE_KEYS_PER_BUCKET 4
75c1b4b26aSCristian Dumitrescu #define TABLE_KEYS_PER_BUCKET_LOG2 2
760c06fa3bSCristian Dumitrescu
778186c0bbSCristian Dumitrescu #define TABLE_BUCKET_USEFUL_SIZE \
788186c0bbSCristian Dumitrescu (TABLE_KEYS_PER_BUCKET * (sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t)))
798186c0bbSCristian Dumitrescu
800c06fa3bSCristian Dumitrescu #define TABLE_BUCKET_PAD_SIZE \
818186c0bbSCristian Dumitrescu (RTE_CACHE_LINE_SIZE - TABLE_BUCKET_USEFUL_SIZE)
820c06fa3bSCristian Dumitrescu
830c06fa3bSCristian Dumitrescu struct table_bucket {
840c06fa3bSCristian Dumitrescu uint32_t time[TABLE_KEYS_PER_BUCKET];
850c06fa3bSCristian Dumitrescu uint32_t sig[TABLE_KEYS_PER_BUCKET];
868186c0bbSCristian Dumitrescu uint8_t key_timeout_id[TABLE_KEYS_PER_BUCKET];
870c06fa3bSCristian Dumitrescu uint8_t pad[TABLE_BUCKET_PAD_SIZE];
88013b4c52SBruce Richardson uint8_t key[];
890c06fa3bSCristian Dumitrescu };
900c06fa3bSCristian Dumitrescu
910c06fa3bSCristian Dumitrescu struct table_params {
920c06fa3bSCristian Dumitrescu /* The real key size. Must be non-zero. */
930c06fa3bSCristian Dumitrescu size_t key_size;
940c06fa3bSCristian Dumitrescu
950d871d7eSCristian Dumitrescu /* The key size upgrated to the next power of 2. */
960c06fa3bSCristian Dumitrescu size_t key_size_pow2;
970c06fa3bSCristian Dumitrescu
980c06fa3bSCristian Dumitrescu /* log2(key_size_pow2). Purpose: avoid multiplication with non-power-of-2 numbers. */
990c06fa3bSCristian Dumitrescu size_t key_size_log2;
1000c06fa3bSCristian Dumitrescu
1010c06fa3bSCristian Dumitrescu /* The key offset within the key buffer. */
1020c06fa3bSCristian Dumitrescu size_t key_offset;
1030c06fa3bSCristian Dumitrescu
1040c06fa3bSCristian Dumitrescu /* The real action data size. */
1050c06fa3bSCristian Dumitrescu size_t action_data_size;
1060c06fa3bSCristian Dumitrescu
1070c06fa3bSCristian Dumitrescu /* The data size, i.e. the 8-byte action_id field plus the action data size, upgraded to the
1080c06fa3bSCristian Dumitrescu * next power of 2.
1090c06fa3bSCristian Dumitrescu */
1100c06fa3bSCristian Dumitrescu size_t data_size_pow2;
1110c06fa3bSCristian Dumitrescu
1120c06fa3bSCristian Dumitrescu /* log2(data_size_pow2). Purpose: avoid multiplication with non-power of 2 numbers. */
1130c06fa3bSCristian Dumitrescu size_t data_size_log2;
1140c06fa3bSCristian Dumitrescu
1150c06fa3bSCristian Dumitrescu /* Number of buckets. Must be a power of 2 to avoid modulo with non-power-of-2 numbers. */
1160c06fa3bSCristian Dumitrescu size_t n_buckets;
1170c06fa3bSCristian Dumitrescu
1180c06fa3bSCristian Dumitrescu /* Bucket mask. Purpose: replace modulo with bitmask and operation. */
1190c06fa3bSCristian Dumitrescu size_t bucket_mask;
1200c06fa3bSCristian Dumitrescu
1210c06fa3bSCristian Dumitrescu /* Total number of key bytes in the bucket, including the key padding bytes. There are
1220c06fa3bSCristian Dumitrescu * (key_size_pow2 - key_size) padding bytes for each key in the bucket.
1230c06fa3bSCristian Dumitrescu */
1240c06fa3bSCristian Dumitrescu size_t bucket_key_all_size;
1250c06fa3bSCristian Dumitrescu
1260c06fa3bSCristian Dumitrescu /* Bucket size. Must be a power of 2 to avoid multiplication with non-power-of-2 number. */
1270c06fa3bSCristian Dumitrescu size_t bucket_size;
1280c06fa3bSCristian Dumitrescu
1290c06fa3bSCristian Dumitrescu /* log2(bucket_size). Purpose: avoid multiplication with non-power of 2 numbers. */
1300c06fa3bSCristian Dumitrescu size_t bucket_size_log2;
1310c06fa3bSCristian Dumitrescu
1320d871d7eSCristian Dumitrescu /* Hash function. */
1330d871d7eSCristian Dumitrescu rte_swx_hash_func_t hash_func;
1340d871d7eSCristian Dumitrescu
1350d871d7eSCristian Dumitrescu /* Key comparison function. */
1360d871d7eSCristian Dumitrescu rte_swx_keycmp_func_t keycmp_func;
1370d871d7eSCristian Dumitrescu
1388186c0bbSCristian Dumitrescu /* Set of all possible key timeout values measured in CPU clock cycles. */
1398186c0bbSCristian Dumitrescu uint64_t key_timeout[RTE_SWX_TABLE_LEARNER_N_KEY_TIMEOUTS_MAX];
1408186c0bbSCristian Dumitrescu
1418186c0bbSCristian Dumitrescu /* Number of key timeout values. */
1428186c0bbSCristian Dumitrescu uint32_t n_key_timeouts;
1430c06fa3bSCristian Dumitrescu
1440c06fa3bSCristian Dumitrescu /* Total memory size. */
1450c06fa3bSCristian Dumitrescu size_t total_size;
1460c06fa3bSCristian Dumitrescu };
1470c06fa3bSCristian Dumitrescu
148*c6552d9aSTyler Retzlaff struct __rte_cache_aligned table {
1490c06fa3bSCristian Dumitrescu /* Table parameters. */
1500c06fa3bSCristian Dumitrescu struct table_params params;
1510c06fa3bSCristian Dumitrescu
1520c06fa3bSCristian Dumitrescu /* Table buckets. */
153013b4c52SBruce Richardson uint8_t buckets[];
154*c6552d9aSTyler Retzlaff };
1550c06fa3bSCristian Dumitrescu
1568186c0bbSCristian Dumitrescu /* The timeout (in cycles) is stored in the table as a 32-bit value by truncating its least
1578186c0bbSCristian Dumitrescu * significant 32 bits. Therefore, to make sure the time is always advancing when adding the timeout
1588186c0bbSCristian Dumitrescu * value on top of the current time, the minimum timeout value is 1^32 cycles, which is 2 seconds on
1598186c0bbSCristian Dumitrescu * a 2 GHz CPU.
1608186c0bbSCristian Dumitrescu */
1618186c0bbSCristian Dumitrescu static uint64_t
timeout_convert(uint32_t timeout_in_seconds)1628186c0bbSCristian Dumitrescu timeout_convert(uint32_t timeout_in_seconds)
1638186c0bbSCristian Dumitrescu {
1648186c0bbSCristian Dumitrescu uint64_t timeout_in_cycles = timeout_in_seconds * rte_get_tsc_hz();
1658186c0bbSCristian Dumitrescu
1668186c0bbSCristian Dumitrescu if (!(timeout_in_cycles >> 32))
1678186c0bbSCristian Dumitrescu timeout_in_cycles = 1LLU << 32;
1688186c0bbSCristian Dumitrescu
1698186c0bbSCristian Dumitrescu return timeout_in_cycles;
1708186c0bbSCristian Dumitrescu }
1718186c0bbSCristian Dumitrescu
1720c06fa3bSCristian Dumitrescu static int
table_params_get(struct table_params * p,struct rte_swx_table_learner_params * params)1730c06fa3bSCristian Dumitrescu table_params_get(struct table_params *p, struct rte_swx_table_learner_params *params)
1740c06fa3bSCristian Dumitrescu {
1758186c0bbSCristian Dumitrescu uint32_t i;
1768186c0bbSCristian Dumitrescu
1770c06fa3bSCristian Dumitrescu /* Check input parameters. */
1780c06fa3bSCristian Dumitrescu if (!params ||
1790c06fa3bSCristian Dumitrescu !params->key_size ||
1800c06fa3bSCristian Dumitrescu !params->n_keys_max ||
1810c06fa3bSCristian Dumitrescu (params->n_keys_max > 1U << 31) ||
1828186c0bbSCristian Dumitrescu !params->key_timeout ||
1838186c0bbSCristian Dumitrescu !params->n_key_timeouts ||
1848186c0bbSCristian Dumitrescu (params->n_key_timeouts > RTE_SWX_TABLE_LEARNER_N_KEY_TIMEOUTS_MAX))
1858186c0bbSCristian Dumitrescu return -EINVAL;
1868186c0bbSCristian Dumitrescu
1870d871d7eSCristian Dumitrescu if (params->key_mask0) {
1880d871d7eSCristian Dumitrescu for (i = 0; i < params->key_size; i++)
1890d871d7eSCristian Dumitrescu if (params->key_mask0[i] != 0xFF)
1900d871d7eSCristian Dumitrescu break;
1910d871d7eSCristian Dumitrescu
1920d871d7eSCristian Dumitrescu if (i < params->key_size)
1930d871d7eSCristian Dumitrescu return -EINVAL;
1940d871d7eSCristian Dumitrescu }
1950d871d7eSCristian Dumitrescu
1968186c0bbSCristian Dumitrescu for (i = 0; i < params->n_key_timeouts; i++)
1978186c0bbSCristian Dumitrescu if (!params->key_timeout[i])
1980c06fa3bSCristian Dumitrescu return -EINVAL;
1990c06fa3bSCristian Dumitrescu
2000c06fa3bSCristian Dumitrescu /* Key. */
2010c06fa3bSCristian Dumitrescu p->key_size = params->key_size;
2020c06fa3bSCristian Dumitrescu
2030c06fa3bSCristian Dumitrescu p->key_size_pow2 = rte_align64pow2(p->key_size);
2040c06fa3bSCristian Dumitrescu
2053d4e27fdSDavid Marchand p->key_size_log2 = rte_ctz64(p->key_size_pow2);
2060c06fa3bSCristian Dumitrescu
2070c06fa3bSCristian Dumitrescu p->key_offset = params->key_offset;
2080c06fa3bSCristian Dumitrescu
2090c06fa3bSCristian Dumitrescu /* Data. */
2100c06fa3bSCristian Dumitrescu p->action_data_size = params->action_data_size;
2110c06fa3bSCristian Dumitrescu
2120c06fa3bSCristian Dumitrescu p->data_size_pow2 = rte_align64pow2(sizeof(uint64_t) + p->action_data_size);
2130c06fa3bSCristian Dumitrescu
2143d4e27fdSDavid Marchand p->data_size_log2 = rte_ctz64(p->data_size_pow2);
2150c06fa3bSCristian Dumitrescu
2160c06fa3bSCristian Dumitrescu /* Buckets. */
2170c06fa3bSCristian Dumitrescu p->n_buckets = rte_align32pow2(params->n_keys_max);
2180c06fa3bSCristian Dumitrescu
2190c06fa3bSCristian Dumitrescu p->bucket_mask = p->n_buckets - 1;
2200c06fa3bSCristian Dumitrescu
2210c06fa3bSCristian Dumitrescu p->bucket_key_all_size = TABLE_KEYS_PER_BUCKET * p->key_size_pow2;
2220c06fa3bSCristian Dumitrescu
2230c06fa3bSCristian Dumitrescu p->bucket_size = rte_align64pow2(sizeof(struct table_bucket) +
2240c06fa3bSCristian Dumitrescu p->bucket_key_all_size +
2250c06fa3bSCristian Dumitrescu TABLE_KEYS_PER_BUCKET * p->data_size_pow2);
2260c06fa3bSCristian Dumitrescu
2273d4e27fdSDavid Marchand p->bucket_size_log2 = rte_ctz64(p->bucket_size);
2280c06fa3bSCristian Dumitrescu
2290d871d7eSCristian Dumitrescu p->hash_func = params->hash_func ? params->hash_func : rte_hash_crc;
2300d871d7eSCristian Dumitrescu
2310d871d7eSCristian Dumitrescu p->keycmp_func = rte_swx_keycmp_func_get(params->key_size);
2320d871d7eSCristian Dumitrescu
2330c06fa3bSCristian Dumitrescu /* Timeout. */
2348186c0bbSCristian Dumitrescu for (i = 0; i < params->n_key_timeouts; i++)
2358186c0bbSCristian Dumitrescu p->key_timeout[i] = timeout_convert(params->key_timeout[i]);
2368186c0bbSCristian Dumitrescu
2378186c0bbSCristian Dumitrescu p->n_key_timeouts = rte_align32pow2(params->n_key_timeouts);
2388186c0bbSCristian Dumitrescu
2398186c0bbSCristian Dumitrescu for ( ; i < p->n_key_timeouts; i++)
2408186c0bbSCristian Dumitrescu p->key_timeout[i] = p->key_timeout[0];
2410c06fa3bSCristian Dumitrescu
2420c06fa3bSCristian Dumitrescu /* Total size. */
2430c06fa3bSCristian Dumitrescu p->total_size = sizeof(struct table) + p->n_buckets * p->bucket_size;
2440c06fa3bSCristian Dumitrescu
2450c06fa3bSCristian Dumitrescu return 0;
2460c06fa3bSCristian Dumitrescu }
2470c06fa3bSCristian Dumitrescu
2480c06fa3bSCristian Dumitrescu static inline struct table_bucket *
table_bucket_get(struct table * t,size_t bucket_id)2490c06fa3bSCristian Dumitrescu table_bucket_get(struct table *t, size_t bucket_id)
2500c06fa3bSCristian Dumitrescu {
2510c06fa3bSCristian Dumitrescu return (struct table_bucket *)&t->buckets[bucket_id << t->params.bucket_size_log2];
2520c06fa3bSCristian Dumitrescu }
2530c06fa3bSCristian Dumitrescu
2540c06fa3bSCristian Dumitrescu static inline uint8_t *
table_bucket_key_get(struct table * t,struct table_bucket * b,size_t bucket_key_pos)2550c06fa3bSCristian Dumitrescu table_bucket_key_get(struct table *t, struct table_bucket *b, size_t bucket_key_pos)
2560c06fa3bSCristian Dumitrescu {
2570c06fa3bSCristian Dumitrescu return &b->key[bucket_key_pos << t->params.key_size_log2];
2580c06fa3bSCristian Dumitrescu }
2590c06fa3bSCristian Dumitrescu
2600c06fa3bSCristian Dumitrescu static inline uint64_t *
table_bucket_data_get(struct table * t,struct table_bucket * b,size_t bucket_key_pos)2610c06fa3bSCristian Dumitrescu table_bucket_data_get(struct table *t, struct table_bucket *b, size_t bucket_key_pos)
2620c06fa3bSCristian Dumitrescu {
2630c06fa3bSCristian Dumitrescu return (uint64_t *)&b->key[t->params.bucket_key_all_size +
2640c06fa3bSCristian Dumitrescu (bucket_key_pos << t->params.data_size_log2)];
2650c06fa3bSCristian Dumitrescu }
2660c06fa3bSCristian Dumitrescu
267c1b4b26aSCristian Dumitrescu static inline size_t
table_entry_id_get(struct table * t,struct table_bucket * b,size_t bucket_key_pos)268c1b4b26aSCristian Dumitrescu table_entry_id_get(struct table *t, struct table_bucket *b, size_t bucket_key_pos)
269c1b4b26aSCristian Dumitrescu {
270c1b4b26aSCristian Dumitrescu size_t bucket_id = ((uint8_t *)b - t->buckets) >> t->params.bucket_size_log2;
271c1b4b26aSCristian Dumitrescu
272c1b4b26aSCristian Dumitrescu return (bucket_id << TABLE_KEYS_PER_BUCKET_LOG2) + bucket_key_pos;
273c1b4b26aSCristian Dumitrescu }
274c1b4b26aSCristian Dumitrescu
2750c06fa3bSCristian Dumitrescu uint64_t
rte_swx_table_learner_footprint_get(struct rte_swx_table_learner_params * params)2760c06fa3bSCristian Dumitrescu rte_swx_table_learner_footprint_get(struct rte_swx_table_learner_params *params)
2770c06fa3bSCristian Dumitrescu {
2780c06fa3bSCristian Dumitrescu struct table_params p;
2790c06fa3bSCristian Dumitrescu int status;
2800c06fa3bSCristian Dumitrescu
2810c06fa3bSCristian Dumitrescu status = table_params_get(&p, params);
2820c06fa3bSCristian Dumitrescu
2830c06fa3bSCristian Dumitrescu return status ? 0 : p.total_size;
2840c06fa3bSCristian Dumitrescu }
2850c06fa3bSCristian Dumitrescu
2860c06fa3bSCristian Dumitrescu void *
rte_swx_table_learner_create(struct rte_swx_table_learner_params * params,int numa_node)2870c06fa3bSCristian Dumitrescu rte_swx_table_learner_create(struct rte_swx_table_learner_params *params, int numa_node)
2880c06fa3bSCristian Dumitrescu {
2890c06fa3bSCristian Dumitrescu struct table_params p;
2900c06fa3bSCristian Dumitrescu struct table *t;
2910c06fa3bSCristian Dumitrescu int status;
2920c06fa3bSCristian Dumitrescu
2930c06fa3bSCristian Dumitrescu /* Check and process the input parameters. */
2940c06fa3bSCristian Dumitrescu status = table_params_get(&p, params);
2950c06fa3bSCristian Dumitrescu if (status)
2960c06fa3bSCristian Dumitrescu return NULL;
2970c06fa3bSCristian Dumitrescu
2980c06fa3bSCristian Dumitrescu /* Memory allocation. */
2990c06fa3bSCristian Dumitrescu t = env_calloc(p.total_size, RTE_CACHE_LINE_SIZE, numa_node);
3000c06fa3bSCristian Dumitrescu if (!t)
3010c06fa3bSCristian Dumitrescu return NULL;
3020c06fa3bSCristian Dumitrescu
3030c06fa3bSCristian Dumitrescu /* Memory initialization. */
3040c06fa3bSCristian Dumitrescu memcpy(&t->params, &p, sizeof(struct table_params));
3050c06fa3bSCristian Dumitrescu
3060c06fa3bSCristian Dumitrescu return t;
3070c06fa3bSCristian Dumitrescu }
3080c06fa3bSCristian Dumitrescu
3090c06fa3bSCristian Dumitrescu void
rte_swx_table_learner_free(void * table)3100c06fa3bSCristian Dumitrescu rte_swx_table_learner_free(void *table)
3110c06fa3bSCristian Dumitrescu {
3120c06fa3bSCristian Dumitrescu struct table *t = table;
3130c06fa3bSCristian Dumitrescu
3140c06fa3bSCristian Dumitrescu if (!t)
3150c06fa3bSCristian Dumitrescu return;
3160c06fa3bSCristian Dumitrescu
3170c06fa3bSCristian Dumitrescu env_free(t, t->params.total_size);
3180c06fa3bSCristian Dumitrescu }
3190c06fa3bSCristian Dumitrescu
3208186c0bbSCristian Dumitrescu int
rte_swx_table_learner_timeout_update(void * table,uint32_t key_timeout_id,uint32_t key_timeout)3218186c0bbSCristian Dumitrescu rte_swx_table_learner_timeout_update(void *table,
3228186c0bbSCristian Dumitrescu uint32_t key_timeout_id,
3238186c0bbSCristian Dumitrescu uint32_t key_timeout)
3248186c0bbSCristian Dumitrescu {
3258186c0bbSCristian Dumitrescu struct table *t = table;
3268186c0bbSCristian Dumitrescu
3278186c0bbSCristian Dumitrescu if (!t ||
3288186c0bbSCristian Dumitrescu (key_timeout_id >= t->params.n_key_timeouts) ||
3298186c0bbSCristian Dumitrescu !key_timeout)
3308186c0bbSCristian Dumitrescu return -EINVAL;
3318186c0bbSCristian Dumitrescu
3328186c0bbSCristian Dumitrescu t->params.key_timeout[key_timeout_id] = timeout_convert(key_timeout);
3338186c0bbSCristian Dumitrescu
3348186c0bbSCristian Dumitrescu return 0;
3358186c0bbSCristian Dumitrescu }
3368186c0bbSCristian Dumitrescu
3370c06fa3bSCristian Dumitrescu struct mailbox {
3380c06fa3bSCristian Dumitrescu /* Writer: lookup state 0. Reader(s): lookup state 1, add(). */
3390c06fa3bSCristian Dumitrescu struct table_bucket *bucket;
3400c06fa3bSCristian Dumitrescu
3410c06fa3bSCristian Dumitrescu /* Writer: lookup state 0. Reader(s): lookup state 1, add(). */
3420c06fa3bSCristian Dumitrescu uint32_t input_sig;
3430c06fa3bSCristian Dumitrescu
344c1b4b26aSCristian Dumitrescu /* Writer: lookup state 0. Reader(s): lookup state 1, add(). */
3450c06fa3bSCristian Dumitrescu uint8_t *input_key;
3460c06fa3bSCristian Dumitrescu
3470c06fa3bSCristian Dumitrescu /* Writer: lookup state 1. Reader(s): add(). Values: 0 = miss; 1 = hit. */
3480c06fa3bSCristian Dumitrescu uint32_t hit;
3490c06fa3bSCristian Dumitrescu
3500c06fa3bSCristian Dumitrescu /* Writer: lookup state 1. Reader(s): add(). Valid only when hit is non-zero. */
3510c06fa3bSCristian Dumitrescu size_t bucket_key_pos;
3520c06fa3bSCristian Dumitrescu
3530c06fa3bSCristian Dumitrescu /* State. */
3540c06fa3bSCristian Dumitrescu int state;
3550c06fa3bSCristian Dumitrescu };
3560c06fa3bSCristian Dumitrescu
3570c06fa3bSCristian Dumitrescu uint64_t
rte_swx_table_learner_mailbox_size_get(void)3580c06fa3bSCristian Dumitrescu rte_swx_table_learner_mailbox_size_get(void)
3590c06fa3bSCristian Dumitrescu {
3600c06fa3bSCristian Dumitrescu return sizeof(struct mailbox);
3610c06fa3bSCristian Dumitrescu }
3620c06fa3bSCristian Dumitrescu
3630c06fa3bSCristian Dumitrescu int
rte_swx_table_learner_lookup(void * table,void * mailbox,uint64_t input_time,uint8_t ** key,uint64_t * action_id,uint8_t ** action_data,size_t * entry_id,int * hit)3640c06fa3bSCristian Dumitrescu rte_swx_table_learner_lookup(void *table,
3650c06fa3bSCristian Dumitrescu void *mailbox,
3660c06fa3bSCristian Dumitrescu uint64_t input_time,
3670c06fa3bSCristian Dumitrescu uint8_t **key,
3680c06fa3bSCristian Dumitrescu uint64_t *action_id,
3690c06fa3bSCristian Dumitrescu uint8_t **action_data,
370c1b4b26aSCristian Dumitrescu size_t *entry_id,
3710c06fa3bSCristian Dumitrescu int *hit)
3720c06fa3bSCristian Dumitrescu {
3730c06fa3bSCristian Dumitrescu struct table *t = table;
3740c06fa3bSCristian Dumitrescu struct mailbox *m = mailbox;
3750c06fa3bSCristian Dumitrescu
3760c06fa3bSCristian Dumitrescu switch (m->state) {
3770c06fa3bSCristian Dumitrescu case 0: {
3780c06fa3bSCristian Dumitrescu uint8_t *input_key;
3790c06fa3bSCristian Dumitrescu struct table_bucket *b;
3800c06fa3bSCristian Dumitrescu size_t bucket_id;
3810c06fa3bSCristian Dumitrescu uint32_t input_sig;
3820c06fa3bSCristian Dumitrescu
3830c06fa3bSCristian Dumitrescu input_key = &(*key)[t->params.key_offset];
3840d871d7eSCristian Dumitrescu input_sig = t->params.hash_func(input_key, t->params.key_size, 0);
3850c06fa3bSCristian Dumitrescu bucket_id = input_sig & t->params.bucket_mask;
3860c06fa3bSCristian Dumitrescu b = table_bucket_get(t, bucket_id);
3870c06fa3bSCristian Dumitrescu
3880c06fa3bSCristian Dumitrescu rte_prefetch0(b);
3890c06fa3bSCristian Dumitrescu rte_prefetch0(&b->key[0]);
3900c06fa3bSCristian Dumitrescu rte_prefetch0(&b->key[RTE_CACHE_LINE_SIZE]);
3910c06fa3bSCristian Dumitrescu
3920c06fa3bSCristian Dumitrescu m->bucket = b;
3930c06fa3bSCristian Dumitrescu m->input_key = input_key;
3940c06fa3bSCristian Dumitrescu m->input_sig = input_sig | 1;
3950c06fa3bSCristian Dumitrescu m->state = 1;
3960c06fa3bSCristian Dumitrescu return 0;
3970c06fa3bSCristian Dumitrescu }
3980c06fa3bSCristian Dumitrescu
3990c06fa3bSCristian Dumitrescu case 1: {
4000c06fa3bSCristian Dumitrescu struct table_bucket *b = m->bucket;
4010c06fa3bSCristian Dumitrescu uint32_t i;
4020c06fa3bSCristian Dumitrescu
4030c06fa3bSCristian Dumitrescu /* Search the input key through the bucket keys. */
4040c06fa3bSCristian Dumitrescu for (i = 0; i < TABLE_KEYS_PER_BUCKET; i++) {
4050c06fa3bSCristian Dumitrescu uint64_t time = b->time[i];
4060c06fa3bSCristian Dumitrescu uint32_t sig = b->sig[i];
4070c06fa3bSCristian Dumitrescu uint8_t *key = table_bucket_key_get(t, b, i);
4080c06fa3bSCristian Dumitrescu
4090c06fa3bSCristian Dumitrescu time <<= 32;
4100c06fa3bSCristian Dumitrescu
4110c06fa3bSCristian Dumitrescu if ((time > input_time) &&
4120c06fa3bSCristian Dumitrescu (sig == m->input_sig) &&
4130d871d7eSCristian Dumitrescu t->params.keycmp_func(key, m->input_key, t->params.key_size)) {
4140c06fa3bSCristian Dumitrescu uint64_t *data = table_bucket_data_get(t, b, i);
4150c06fa3bSCristian Dumitrescu
4160c06fa3bSCristian Dumitrescu /* Hit. */
4170c06fa3bSCristian Dumitrescu rte_prefetch0(data);
4180c06fa3bSCristian Dumitrescu
4190c06fa3bSCristian Dumitrescu m->hit = 1;
4200c06fa3bSCristian Dumitrescu m->bucket_key_pos = i;
4210c06fa3bSCristian Dumitrescu m->state = 0;
4220c06fa3bSCristian Dumitrescu
4230c06fa3bSCristian Dumitrescu *action_id = data[0];
4240c06fa3bSCristian Dumitrescu *action_data = (uint8_t *)&data[1];
425c1b4b26aSCristian Dumitrescu *entry_id = table_entry_id_get(t, b, i);
4260c06fa3bSCristian Dumitrescu *hit = 1;
4270c06fa3bSCristian Dumitrescu return 1;
4280c06fa3bSCristian Dumitrescu }
4290c06fa3bSCristian Dumitrescu }
4300c06fa3bSCristian Dumitrescu
4310c06fa3bSCristian Dumitrescu /* Miss. */
4320c06fa3bSCristian Dumitrescu m->hit = 0;
4330c06fa3bSCristian Dumitrescu m->state = 0;
4340c06fa3bSCristian Dumitrescu
4350c06fa3bSCristian Dumitrescu *hit = 0;
4360c06fa3bSCristian Dumitrescu return 1;
4370c06fa3bSCristian Dumitrescu }
4380c06fa3bSCristian Dumitrescu
4390c06fa3bSCristian Dumitrescu default:
4400c06fa3bSCristian Dumitrescu /* This state should never be reached. Miss. */
4410c06fa3bSCristian Dumitrescu m->hit = 0;
4420c06fa3bSCristian Dumitrescu m->state = 0;
4430c06fa3bSCristian Dumitrescu
4440c06fa3bSCristian Dumitrescu *hit = 0;
4450c06fa3bSCristian Dumitrescu return 1;
4460c06fa3bSCristian Dumitrescu }
4470c06fa3bSCristian Dumitrescu }
4480c06fa3bSCristian Dumitrescu
4498186c0bbSCristian Dumitrescu void
rte_swx_table_learner_rearm(void * table,void * mailbox,uint64_t input_time)4508186c0bbSCristian Dumitrescu rte_swx_table_learner_rearm(void *table,
4518186c0bbSCristian Dumitrescu void *mailbox,
4528186c0bbSCristian Dumitrescu uint64_t input_time)
4538186c0bbSCristian Dumitrescu {
4548186c0bbSCristian Dumitrescu struct table *t = table;
4558186c0bbSCristian Dumitrescu struct mailbox *m = mailbox;
4568186c0bbSCristian Dumitrescu struct table_bucket *b;
4578186c0bbSCristian Dumitrescu size_t bucket_key_pos;
4588186c0bbSCristian Dumitrescu uint64_t key_timeout;
4598186c0bbSCristian Dumitrescu uint32_t key_timeout_id;
4608186c0bbSCristian Dumitrescu
4618186c0bbSCristian Dumitrescu if (!m->hit)
4628186c0bbSCristian Dumitrescu return;
4638186c0bbSCristian Dumitrescu
4648186c0bbSCristian Dumitrescu b = m->bucket;
4658186c0bbSCristian Dumitrescu bucket_key_pos = m->bucket_key_pos;
4668186c0bbSCristian Dumitrescu
4678186c0bbSCristian Dumitrescu key_timeout_id = b->key_timeout_id[bucket_key_pos];
4688186c0bbSCristian Dumitrescu key_timeout = t->params.key_timeout[key_timeout_id];
4698186c0bbSCristian Dumitrescu b->time[bucket_key_pos] = (input_time + key_timeout) >> 32;
4708186c0bbSCristian Dumitrescu }
4718186c0bbSCristian Dumitrescu
4728186c0bbSCristian Dumitrescu void
rte_swx_table_learner_rearm_new(void * table,void * mailbox,uint64_t input_time,uint32_t key_timeout_id)4738186c0bbSCristian Dumitrescu rte_swx_table_learner_rearm_new(void *table,
4748186c0bbSCristian Dumitrescu void *mailbox,
4758186c0bbSCristian Dumitrescu uint64_t input_time,
4768186c0bbSCristian Dumitrescu uint32_t key_timeout_id)
4778186c0bbSCristian Dumitrescu {
4788186c0bbSCristian Dumitrescu struct table *t = table;
4798186c0bbSCristian Dumitrescu struct mailbox *m = mailbox;
4808186c0bbSCristian Dumitrescu struct table_bucket *b;
4818186c0bbSCristian Dumitrescu size_t bucket_key_pos;
4828186c0bbSCristian Dumitrescu uint64_t key_timeout;
4838186c0bbSCristian Dumitrescu
4848186c0bbSCristian Dumitrescu if (!m->hit)
4858186c0bbSCristian Dumitrescu return;
4868186c0bbSCristian Dumitrescu
4878186c0bbSCristian Dumitrescu b = m->bucket;
4888186c0bbSCristian Dumitrescu bucket_key_pos = m->bucket_key_pos;
4898186c0bbSCristian Dumitrescu
4908186c0bbSCristian Dumitrescu key_timeout_id &= t->params.n_key_timeouts - 1;
4918186c0bbSCristian Dumitrescu key_timeout = t->params.key_timeout[key_timeout_id];
4928186c0bbSCristian Dumitrescu b->time[bucket_key_pos] = (input_time + key_timeout) >> 32;
4938186c0bbSCristian Dumitrescu b->key_timeout_id[bucket_key_pos] = (uint8_t)key_timeout_id;
4948186c0bbSCristian Dumitrescu }
4958186c0bbSCristian Dumitrescu
4960c06fa3bSCristian Dumitrescu uint32_t
rte_swx_table_learner_add(void * table,void * mailbox,uint64_t input_time,uint64_t action_id,uint8_t * action_data,uint32_t key_timeout_id)4970c06fa3bSCristian Dumitrescu rte_swx_table_learner_add(void *table,
4980c06fa3bSCristian Dumitrescu void *mailbox,
4990c06fa3bSCristian Dumitrescu uint64_t input_time,
5000c06fa3bSCristian Dumitrescu uint64_t action_id,
5018186c0bbSCristian Dumitrescu uint8_t *action_data,
5028186c0bbSCristian Dumitrescu uint32_t key_timeout_id)
5030c06fa3bSCristian Dumitrescu {
5040c06fa3bSCristian Dumitrescu struct table *t = table;
5050c06fa3bSCristian Dumitrescu struct mailbox *m = mailbox;
5060c06fa3bSCristian Dumitrescu struct table_bucket *b = m->bucket;
5078186c0bbSCristian Dumitrescu uint64_t key_timeout;
5080c06fa3bSCristian Dumitrescu uint32_t i;
5090c06fa3bSCristian Dumitrescu
5108186c0bbSCristian Dumitrescu /* Adjust the key timeout ID to fit the valid range. */
5118186c0bbSCristian Dumitrescu key_timeout_id &= t->params.n_key_timeouts - 1;
5128186c0bbSCristian Dumitrescu key_timeout = t->params.key_timeout[key_timeout_id];
5138186c0bbSCristian Dumitrescu
5148186c0bbSCristian Dumitrescu /* Lookup hit: The following bucket fields need to be updated:
5158186c0bbSCristian Dumitrescu * - key (key, sig): NO (already correctly set).
5168186c0bbSCristian Dumitrescu * - key timeout (key_timeout_id, time): YES.
5178186c0bbSCristian Dumitrescu * - key data (data): YES.
5180c06fa3bSCristian Dumitrescu */
5190c06fa3bSCristian Dumitrescu if (m->hit) {
5208186c0bbSCristian Dumitrescu size_t bucket_key_pos = m->bucket_key_pos;
5218186c0bbSCristian Dumitrescu uint64_t *data = table_bucket_data_get(t, b, bucket_key_pos);
5228186c0bbSCristian Dumitrescu
5238186c0bbSCristian Dumitrescu /* Install the key timeout. */
5248186c0bbSCristian Dumitrescu b->time[bucket_key_pos] = (input_time + key_timeout) >> 32;
5258186c0bbSCristian Dumitrescu b->key_timeout_id[bucket_key_pos] = (uint8_t)key_timeout_id;
5260c06fa3bSCristian Dumitrescu
5270c06fa3bSCristian Dumitrescu /* Install the key data. */
5280c06fa3bSCristian Dumitrescu data[0] = action_id;
5290c06fa3bSCristian Dumitrescu if (t->params.action_data_size && action_data)
5300c06fa3bSCristian Dumitrescu memcpy(&data[1], action_data, t->params.action_data_size);
5310c06fa3bSCristian Dumitrescu
5320c06fa3bSCristian Dumitrescu return 0;
5330c06fa3bSCristian Dumitrescu }
5340c06fa3bSCristian Dumitrescu
5350c06fa3bSCristian Dumitrescu /* Lookup miss: Search for a free position in the current bucket and install the key. */
5360c06fa3bSCristian Dumitrescu for (i = 0; i < TABLE_KEYS_PER_BUCKET; i++) {
5370c06fa3bSCristian Dumitrescu uint64_t time = b->time[i];
5380c06fa3bSCristian Dumitrescu
5390c06fa3bSCristian Dumitrescu time <<= 32;
5400c06fa3bSCristian Dumitrescu
5410c06fa3bSCristian Dumitrescu /* Free position: Either there was never a key installed here, so the key time is
5420c06fa3bSCristian Dumitrescu * set to zero (the init value), which is always less than the current time, or this
5430c06fa3bSCristian Dumitrescu * position was used before, but the key expired (the key time is in the past).
5440c06fa3bSCristian Dumitrescu */
5450c06fa3bSCristian Dumitrescu if (time < input_time) {
5460c06fa3bSCristian Dumitrescu uint8_t *key = table_bucket_key_get(t, b, i);
5470c06fa3bSCristian Dumitrescu uint64_t *data = table_bucket_data_get(t, b, i);
5480c06fa3bSCristian Dumitrescu
5498186c0bbSCristian Dumitrescu /* Install the key and the key timeout. */
5508186c0bbSCristian Dumitrescu b->time[i] = (input_time + key_timeout) >> 32;
5510c06fa3bSCristian Dumitrescu b->sig[i] = m->input_sig;
5528186c0bbSCristian Dumitrescu b->key_timeout_id[i] = (uint8_t)key_timeout_id;
5530d871d7eSCristian Dumitrescu table_keycpy(key, m->input_key, t->params.key_size);
5540c06fa3bSCristian Dumitrescu
5550c06fa3bSCristian Dumitrescu /* Install the key data. */
5560c06fa3bSCristian Dumitrescu data[0] = action_id;
5570c06fa3bSCristian Dumitrescu if (t->params.action_data_size && action_data)
5580c06fa3bSCristian Dumitrescu memcpy(&data[1], action_data, t->params.action_data_size);
5590c06fa3bSCristian Dumitrescu
5600c06fa3bSCristian Dumitrescu /* Mailbox. */
5610c06fa3bSCristian Dumitrescu m->hit = 1;
5620c06fa3bSCristian Dumitrescu m->bucket_key_pos = i;
5630c06fa3bSCristian Dumitrescu
5640c06fa3bSCristian Dumitrescu return 0;
5650c06fa3bSCristian Dumitrescu }
5660c06fa3bSCristian Dumitrescu }
5670c06fa3bSCristian Dumitrescu
5680c06fa3bSCristian Dumitrescu /* Bucket full. */
5690c06fa3bSCristian Dumitrescu return 1;
5700c06fa3bSCristian Dumitrescu }
5710c06fa3bSCristian Dumitrescu
5720c06fa3bSCristian Dumitrescu void
rte_swx_table_learner_delete(void * table __rte_unused,void * mailbox)5730c06fa3bSCristian Dumitrescu rte_swx_table_learner_delete(void *table __rte_unused,
5740c06fa3bSCristian Dumitrescu void *mailbox)
5750c06fa3bSCristian Dumitrescu {
5760c06fa3bSCristian Dumitrescu struct mailbox *m = mailbox;
5770c06fa3bSCristian Dumitrescu
5780c06fa3bSCristian Dumitrescu if (m->hit) {
5790c06fa3bSCristian Dumitrescu struct table_bucket *b = m->bucket;
5800c06fa3bSCristian Dumitrescu
5810c06fa3bSCristian Dumitrescu /* Expire the key. */
5820c06fa3bSCristian Dumitrescu b->time[m->bucket_key_pos] = 0;
5830c06fa3bSCristian Dumitrescu
5840c06fa3bSCristian Dumitrescu /* Mailbox. */
5850c06fa3bSCristian Dumitrescu m->hit = 0;
5860c06fa3bSCristian Dumitrescu }
5870c06fa3bSCristian Dumitrescu }
588