Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2014 Intel Corporation
3 : : */
4 : :
5 : : #include <stdint.h>
6 : : #include <stdio.h>
7 : : #include <string.h>
8 : : #include <errno.h>
9 : : #include <sys/queue.h>
10 : :
11 : : #include <eal_export.h>
12 : : #include <rte_cpuflags.h>
13 : : #include <rte_eal_memconfig.h>
14 : : #include <rte_malloc.h>
15 : : #include <rte_common.h>
16 : : #include <rte_errno.h>
17 : : #include <rte_string_fns.h>
18 : : #include <rte_log.h>
19 : : #include <rte_tailq.h>
20 : :
21 : : #include "rte_fbk_hash.h"
22 : :
23 [ - + ]: 252 : RTE_LOG_REGISTER_SUFFIX(fbk_hash_logtype, fbk, INFO);
24 : : #define RTE_LOGTYPE_HASH fbk_hash_logtype
25 : : #define HASH_LOG(level, ...) \
26 : : RTE_LOG_LINE(level, HASH, "" __VA_ARGS__)
27 : :
28 : : TAILQ_HEAD(rte_fbk_hash_list, rte_tailq_entry);
29 : :
30 : : static struct rte_tailq_elem rte_fbk_hash_tailq = {
31 : : .name = "RTE_FBK_HASH",
32 : : };
33 [ - + ]: 252 : EAL_REGISTER_TAILQ(rte_fbk_hash_tailq)
34 : :
35 : : /**
36 : : * Performs a lookup for an existing hash table, and returns a pointer to
37 : : * the table if found.
38 : : *
39 : : * @param name
40 : : * Name of the hash table to find
41 : : *
42 : : * @return
43 : : * pointer to hash table structure or NULL on error.
44 : : */
45 : : RTE_EXPORT_SYMBOL(rte_fbk_hash_find_existing)
46 : : struct rte_fbk_hash_table *
47 : 100 : rte_fbk_hash_find_existing(const char *name)
48 : : {
49 : : struct rte_fbk_hash_table *h = NULL;
50 : : struct rte_tailq_entry *te;
51 : : struct rte_fbk_hash_list *fbk_hash_list;
52 : :
53 : 100 : fbk_hash_list = RTE_TAILQ_CAST(rte_fbk_hash_tailq.head,
54 : : rte_fbk_hash_list);
55 : :
56 : 100 : rte_mcfg_tailq_read_lock();
57 [ + + ]: 179 : TAILQ_FOREACH(te, fbk_hash_list, next) {
58 : 118 : h = (struct rte_fbk_hash_table *) te->data;
59 [ + + ]: 118 : if (strncmp(name, h->name, RTE_FBK_HASH_NAMESIZE) == 0)
60 : : break;
61 : : }
62 : 94 : rte_mcfg_tailq_read_unlock();
63 [ + + ]: 94 : if (te == NULL) {
64 : 66 : rte_errno = ENOENT;
65 : 66 : return NULL;
66 : : }
67 : : return h;
68 : : }
69 : :
70 : : /**
71 : : * Create a new hash table for use with four byte keys.
72 : : *
73 : : * @param params
74 : : * Parameters used in creation of hash table.
75 : : *
76 : : * @return
77 : : * Pointer to hash table structure that is used in future hash table
78 : : * operations, or NULL on error.
79 : : */
80 : : RTE_EXPORT_SYMBOL(rte_fbk_hash_create)
81 : : struct rte_fbk_hash_table *
82 : 56 : rte_fbk_hash_create(const struct rte_fbk_hash_params *params)
83 : : {
84 : : struct rte_fbk_hash_table *ht = NULL;
85 : : struct rte_tailq_entry *te;
86 : : char hash_name[RTE_FBK_HASH_NAMESIZE];
87 : 56 : const uint32_t mem_size =
88 : 56 : sizeof(*ht) + (sizeof(ht->t[0]) * params->entries);
89 : : uint32_t i;
90 : : struct rte_fbk_hash_list *fbk_hash_list;
91 : : rte_fbk_hash_fn default_hash_func = (rte_fbk_hash_fn)rte_jhash_1word;
92 : :
93 [ + + ]: 56 : fbk_hash_list = RTE_TAILQ_CAST(rte_fbk_hash_tailq.head,
94 : : rte_fbk_hash_list);
95 : :
96 : : /* Error checking of parameters. */
97 : : if ((!rte_is_power_of_2(params->entries)) ||
98 [ + + ]: 52 : (!rte_is_power_of_2(params->entries_per_bucket)) ||
99 : : (params->entries == 0) ||
100 [ + + ]: 50 : (params->entries_per_bucket == 0) ||
101 [ + + ]: 49 : (params->entries_per_bucket > params->entries) ||
102 [ + + ]: 48 : (params->entries > RTE_FBK_HASH_ENTRIES_MAX) ||
103 : : (params->entries_per_bucket > RTE_FBK_HASH_ENTRIES_PER_BUCKET_MAX)){
104 : 9 : rte_errno = EINVAL;
105 : 9 : return NULL;
106 : : }
107 : :
108 : 47 : snprintf(hash_name, sizeof(hash_name), "FBK_%s", params->name);
109 : :
110 : 47 : rte_mcfg_tailq_write_lock();
111 : :
112 : : /* guarantee there's no existing */
113 [ + + ]: 87 : TAILQ_FOREACH(te, fbk_hash_list, next) {
114 : 48 : ht = (struct rte_fbk_hash_table *) te->data;
115 [ + + ]: 48 : if (strncmp(params->name, ht->name, RTE_FBK_HASH_NAMESIZE) == 0)
116 : : break;
117 : : }
118 : : ht = NULL;
119 [ + + ]: 47 : if (te != NULL) {
120 : 8 : rte_errno = EEXIST;
121 : 8 : goto exit;
122 : : }
123 : :
124 : 39 : te = rte_zmalloc("FBK_HASH_TAILQ_ENTRY", sizeof(*te), 0);
125 [ - + ]: 39 : if (te == NULL) {
126 : 0 : HASH_LOG(ERR, "Failed to allocate tailq entry");
127 : 0 : goto exit;
128 : : }
129 : :
130 : : /* Allocate memory for table. */
131 : 39 : ht = rte_zmalloc_socket(hash_name, mem_size,
132 : 39 : 0, params->socket_id);
133 [ - + ]: 39 : if (ht == NULL) {
134 : 0 : HASH_LOG(ERR, "Failed to allocate fbk hash table");
135 : 0 : rte_free(te);
136 : 0 : goto exit;
137 : : }
138 : :
139 : : /* Default hash function */
140 : : #if defined(RTE_ARCH_X86)
141 : : default_hash_func = (rte_fbk_hash_fn)rte_hash_crc_4byte;
142 : : #elif defined(RTE_ARCH_ARM64)
143 : : if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_CRC32))
144 : : default_hash_func = (rte_fbk_hash_fn)rte_hash_crc_4byte;
145 : : #endif
146 : :
147 : : /* Set up hash table context. */
148 : 39 : strlcpy(ht->name, params->name, sizeof(ht->name));
149 : 39 : ht->entries = params->entries;
150 : 39 : ht->entries_per_bucket = params->entries_per_bucket;
151 : 39 : ht->used_entries = 0;
152 : 39 : ht->bucket_mask = (params->entries / params->entries_per_bucket) - 1;
153 : 39 : for (ht->bucket_shift = 0, i = 1;
154 [ + + ]: 116 : (params->entries_per_bucket & i) == 0;
155 : 77 : ht->bucket_shift++, i <<= 1)
156 : : ; /* empty loop body */
157 : :
158 [ + + ]: 39 : if (params->hash_func != NULL) {
159 : 34 : ht->hash_func = params->hash_func;
160 : 34 : ht->init_val = params->init_val;
161 : : }
162 : : else {
163 : 5 : ht->hash_func = default_hash_func;
164 : 5 : ht->init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT;
165 : : }
166 : :
167 : 39 : te->data = (void *) ht;
168 : :
169 : 39 : TAILQ_INSERT_TAIL(fbk_hash_list, te, next);
170 : :
171 : 47 : exit:
172 : 47 : rte_mcfg_tailq_write_unlock();
173 : :
174 : 47 : return ht;
175 : : }
176 : :
177 : : /**
178 : : * Free all memory used by a hash table.
179 : : *
180 : : * @param ht
181 : : * Hash table to deallocate.
182 : : */
183 : : RTE_EXPORT_SYMBOL(rte_fbk_hash_free)
184 : : void
185 : 42 : rte_fbk_hash_free(struct rte_fbk_hash_table *ht)
186 : : {
187 : : struct rte_tailq_entry *te;
188 : : struct rte_fbk_hash_list *fbk_hash_list;
189 : :
190 [ + + ]: 42 : if (ht == NULL)
191 : : return;
192 : :
193 : 39 : fbk_hash_list = RTE_TAILQ_CAST(rte_fbk_hash_tailq.head,
194 : : rte_fbk_hash_list);
195 : :
196 : 39 : rte_mcfg_tailq_write_lock();
197 : :
198 : : /* find out tailq entry */
199 [ + - ]: 73 : TAILQ_FOREACH(te, fbk_hash_list, next) {
200 [ + + ]: 73 : if (te->data == (void *) ht)
201 : : break;
202 : : }
203 : :
204 [ - + ]: 39 : if (te == NULL) {
205 : 0 : rte_mcfg_tailq_write_unlock();
206 : 0 : return;
207 : : }
208 : :
209 [ + + ]: 39 : TAILQ_REMOVE(fbk_hash_list, te, next);
210 : :
211 : 39 : rte_mcfg_tailq_write_unlock();
212 : :
213 : 39 : rte_free(ht);
214 : 39 : rte_free(te);
215 : : }
|