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