Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2019 Intel Corporation
3 : : */
4 : :
5 : : #include <string.h>
6 : :
7 : : #include <eal_export.h>
8 : : #include <rte_eal_memconfig.h>
9 : : #include <rte_errno.h>
10 : : #include <rte_hash.h>
11 : : #include <rte_hash_crc.h>
12 : : #include <rte_malloc.h>
13 : : #include <rte_random.h>
14 : : #include <rte_tailq.h>
15 : :
16 : : #include "rte_ipsec_sad.h"
17 : :
18 : : /*
19 : : * Rules are stored in three hash tables depending on key_type.
20 : : * Each rule will also be stored in SPI_ONLY table.
21 : : * for each data entry within this table last two bits are reserved to
22 : : * indicate presence of entries with the same SPI in DIP and DIP+SIP tables.
23 : : */
24 : :
25 : : #define SAD_PREFIX "SAD_"
26 : : /* "SAD_<name>" */
27 : : #define SAD_FORMAT SAD_PREFIX "%s"
28 : :
29 : : #define DEFAULT_HASH_FUNC rte_hash_crc
30 : : #define MIN_HASH_ENTRIES 8U /* From rte_cuckoo_hash.h */
31 : :
32 : : struct hash_cnt {
33 : : uint32_t cnt_dip;
34 : : uint32_t cnt_dip_sip;
35 : : };
36 : :
37 : : struct rte_ipsec_sad {
38 : : char name[RTE_IPSEC_SAD_NAMESIZE];
39 : : struct rte_hash *hash[RTE_IPSEC_SAD_KEY_TYPE_MASK];
40 : : uint32_t keysize[RTE_IPSEC_SAD_KEY_TYPE_MASK];
41 : : uint32_t init_val;
42 : : /* Array to track number of more specific rules
43 : : * (spi_dip or spi_dip_sip). Used only in add/delete
44 : : * as a helper struct.
45 : : */
46 : : struct hash_cnt cnt_arr[];
47 : : };
48 : :
49 : : TAILQ_HEAD(rte_ipsec_sad_list, rte_tailq_entry);
50 : : static struct rte_tailq_elem rte_ipsec_sad_tailq = {
51 : : .name = "RTE_IPSEC_SAD",
52 : : };
53 [ - + ]: 252 : EAL_REGISTER_TAILQ(rte_ipsec_sad_tailq)
54 : :
55 : : #define SET_BIT(ptr, bit) (void *)((uintptr_t)(ptr) | (uintptr_t)(bit))
56 : : #define CLEAR_BIT(ptr, bit) (void *)((uintptr_t)(ptr) & ~(uintptr_t)(bit))
57 : : #define GET_BIT(ptr, bit) (void *)((uintptr_t)(ptr) & (uintptr_t)(bit))
58 : :
59 : : /*
60 : : * @internal helper function
61 : : * Add a rule of type SPI_DIP or SPI_DIP_SIP.
62 : : * Inserts a rule into an appropriate hash table,
63 : : * updates the value for a given SPI in SPI_ONLY hash table
64 : : * reflecting presence of more specific rule type in two LSBs.
65 : : * Updates a counter that reflects the number of rules with the same SPI.
66 : : */
67 : : static inline int
68 : 0 : add_specific(struct rte_ipsec_sad *sad, const void *key,
69 : : int key_type, void *sa)
70 : : {
71 : : void *tmp_val;
72 : : int ret, notexist;
73 : :
74 : : /* Check if the key is present in the table.
75 : : * Need for further accaunting in cnt_arr
76 : : */
77 : 0 : ret = rte_hash_lookup_with_hash(sad->hash[key_type], key,
78 : : rte_hash_crc(key, sad->keysize[key_type], sad->init_val));
79 : 0 : notexist = (ret == -ENOENT);
80 : :
81 : : /* Add an SA to the corresponding table.*/
82 : 0 : ret = rte_hash_add_key_with_hash_data(sad->hash[key_type], key,
83 : : rte_hash_crc(key, sad->keysize[key_type], sad->init_val), sa);
84 [ # # ]: 0 : if (ret != 0)
85 : : return ret;
86 : :
87 : : /* Check if there is an entry in SPI only table with the same SPI */
88 : 0 : ret = rte_hash_lookup_with_hash_data(sad->hash[RTE_IPSEC_SAD_SPI_ONLY],
89 : : key, rte_hash_crc(key, sad->keysize[RTE_IPSEC_SAD_SPI_ONLY],
90 : : sad->init_val), &tmp_val);
91 [ # # ]: 0 : if (ret < 0)
92 : 0 : tmp_val = NULL;
93 : 0 : tmp_val = SET_BIT(tmp_val, key_type);
94 : :
95 : : /* Add an entry into SPI only table */
96 : 0 : ret = rte_hash_add_key_with_hash_data(
97 : 0 : sad->hash[RTE_IPSEC_SAD_SPI_ONLY], key,
98 : : rte_hash_crc(key, sad->keysize[RTE_IPSEC_SAD_SPI_ONLY],
99 : : sad->init_val), tmp_val);
100 [ # # ]: 0 : if (ret != 0)
101 : : return ret;
102 : :
103 : : /* Update a counter for a given SPI */
104 : 0 : ret = rte_hash_lookup_with_hash(sad->hash[RTE_IPSEC_SAD_SPI_ONLY], key,
105 : : rte_hash_crc(key, sad->keysize[RTE_IPSEC_SAD_SPI_ONLY],
106 : : sad->init_val));
107 [ # # ]: 0 : if (ret < 0)
108 : : return ret;
109 [ # # ]: 0 : if (key_type == RTE_IPSEC_SAD_SPI_DIP)
110 : 0 : sad->cnt_arr[ret].cnt_dip += notexist;
111 : : else
112 : 0 : sad->cnt_arr[ret].cnt_dip_sip += notexist;
113 : :
114 : : return 0;
115 : : }
116 : :
117 : : RTE_EXPORT_SYMBOL(rte_ipsec_sad_add)
118 : : int
119 : 0 : rte_ipsec_sad_add(struct rte_ipsec_sad *sad,
120 : : const union rte_ipsec_sad_key *key,
121 : : int key_type, void *sa)
122 : : {
123 : : void *tmp_val;
124 : : int ret;
125 : :
126 [ # # # # ]: 0 : if ((sad == NULL) || (key == NULL) || (sa == NULL) ||
127 : : /* sa must be 4 byte aligned */
128 [ # # ]: 0 : (GET_BIT(sa, RTE_IPSEC_SAD_KEY_TYPE_MASK) != 0))
129 : : return -EINVAL;
130 : :
131 : : /*
132 : : * Rules are stored in three hash tables depending on key_type.
133 : : * All rules will also have an entry in SPI_ONLY table, with entry
134 : : * value's two LSB's also indicating presence of rule with this SPI
135 : : * in other tables.
136 : : */
137 [ # # # ]: 0 : switch (key_type) {
138 : 0 : case(RTE_IPSEC_SAD_SPI_ONLY):
139 : 0 : ret = rte_hash_lookup_with_hash_data(sad->hash[key_type],
140 : : key, rte_hash_crc(key, sad->keysize[key_type],
141 : : sad->init_val), &tmp_val);
142 [ # # ]: 0 : if (ret >= 0)
143 : 0 : tmp_val = SET_BIT(sa, GET_BIT(tmp_val,
144 : : RTE_IPSEC_SAD_KEY_TYPE_MASK));
145 : : else
146 : 0 : tmp_val = sa;
147 : 0 : ret = rte_hash_add_key_with_hash_data(sad->hash[key_type],
148 : : key, rte_hash_crc(key, sad->keysize[key_type],
149 : : sad->init_val), tmp_val);
150 : 0 : return ret;
151 : 0 : case(RTE_IPSEC_SAD_SPI_DIP):
152 : : case(RTE_IPSEC_SAD_SPI_DIP_SIP):
153 : 0 : return add_specific(sad, key, key_type, sa);
154 : : default:
155 : : return -EINVAL;
156 : : }
157 : : }
158 : :
159 : : /*
160 : : * @internal helper function
161 : : * Delete a rule of type SPI_DIP or SPI_DIP_SIP.
162 : : * Deletes an entry from an appropriate hash table and decrements
163 : : * an entry counter for given SPI.
164 : : * If entry to remove is the last one with given SPI within the table,
165 : : * then it will also update related entry in SPI_ONLY table.
166 : : * Removes an entry from SPI_ONLY hash table if there no rule left
167 : : * for this SPI in any table.
168 : : */
169 : : static inline int
170 : 0 : del_specific(struct rte_ipsec_sad *sad, const void *key, int key_type)
171 : : {
172 : : void *tmp_val;
173 : : int ret;
174 : : uint32_t *cnt;
175 : :
176 : : /* Remove an SA from the corresponding table.*/
177 : 0 : ret = rte_hash_del_key_with_hash(sad->hash[key_type], key,
178 : : rte_hash_crc(key, sad->keysize[key_type], sad->init_val));
179 [ # # ]: 0 : if (ret < 0)
180 : : return ret;
181 : :
182 : : /* Get an index of cnt_arr entry for a given SPI */
183 : 0 : ret = rte_hash_lookup_with_hash_data(sad->hash[RTE_IPSEC_SAD_SPI_ONLY],
184 : : key, rte_hash_crc(key, sad->keysize[RTE_IPSEC_SAD_SPI_ONLY],
185 : : sad->init_val), &tmp_val);
186 [ # # ]: 0 : if (ret < 0)
187 : : return ret;
188 : : cnt = (key_type == RTE_IPSEC_SAD_SPI_DIP) ?
189 [ # # ]: 0 : &sad->cnt_arr[ret].cnt_dip :
190 : : &sad->cnt_arr[ret].cnt_dip_sip;
191 [ # # ]: 0 : if (--(*cnt) != 0)
192 : : return 0;
193 : :
194 : : /* corresponding counter is 0, clear the bit indicating
195 : : * the presence of more specific rule for a given SPI.
196 : : */
197 : 0 : tmp_val = CLEAR_BIT(tmp_val, key_type);
198 : :
199 : : /* if there are no rules left with same SPI,
200 : : * remove an entry from SPI_only table
201 : : */
202 [ # # ]: 0 : if (tmp_val == NULL)
203 : 0 : ret = rte_hash_del_key_with_hash(
204 : 0 : sad->hash[RTE_IPSEC_SAD_SPI_ONLY], key,
205 : : rte_hash_crc(key, sad->keysize[RTE_IPSEC_SAD_SPI_ONLY],
206 : : sad->init_val));
207 : : else
208 : 0 : ret = rte_hash_add_key_with_hash_data(
209 : 0 : sad->hash[RTE_IPSEC_SAD_SPI_ONLY], key,
210 : : rte_hash_crc(key, sad->keysize[RTE_IPSEC_SAD_SPI_ONLY],
211 : : sad->init_val), tmp_val);
212 : : if (ret < 0)
213 : : return ret;
214 : : return 0;
215 : : }
216 : :
217 : : RTE_EXPORT_SYMBOL(rte_ipsec_sad_del)
218 : : int
219 : 0 : rte_ipsec_sad_del(struct rte_ipsec_sad *sad,
220 : : const union rte_ipsec_sad_key *key,
221 : : int key_type)
222 : : {
223 : : void *tmp_val;
224 : : int ret;
225 : :
226 [ # # ]: 0 : if ((sad == NULL) || (key == NULL))
227 : : return -EINVAL;
228 [ # # # ]: 0 : switch (key_type) {
229 : 0 : case(RTE_IPSEC_SAD_SPI_ONLY):
230 : 0 : ret = rte_hash_lookup_with_hash_data(sad->hash[key_type],
231 : : key, rte_hash_crc(key, sad->keysize[key_type],
232 : : sad->init_val), &tmp_val);
233 [ # # ]: 0 : if (ret < 0)
234 : : return ret;
235 [ # # ]: 0 : if (GET_BIT(tmp_val, RTE_IPSEC_SAD_KEY_TYPE_MASK) == 0) {
236 : 0 : ret = rte_hash_del_key_with_hash(sad->hash[key_type],
237 : : key, rte_hash_crc(key, sad->keysize[key_type],
238 : : sad->init_val));
239 : 0 : ret = ret < 0 ? ret : 0;
240 : : } else {
241 : 0 : tmp_val = GET_BIT(tmp_val,
242 : : RTE_IPSEC_SAD_KEY_TYPE_MASK);
243 : 0 : ret = rte_hash_add_key_with_hash_data(
244 : 0 : sad->hash[key_type], key,
245 : : rte_hash_crc(key, sad->keysize[key_type],
246 : : sad->init_val), tmp_val);
247 : : }
248 : : return ret;
249 : 0 : case(RTE_IPSEC_SAD_SPI_DIP):
250 : : case(RTE_IPSEC_SAD_SPI_DIP_SIP):
251 : 0 : return del_specific(sad, key, key_type);
252 : : default:
253 : : return -EINVAL;
254 : : }
255 : : }
256 : :
257 : : RTE_EXPORT_SYMBOL(rte_ipsec_sad_create)
258 : : struct rte_ipsec_sad *
259 : 0 : rte_ipsec_sad_create(const char *name, const struct rte_ipsec_sad_conf *conf)
260 : : {
261 : : char hash_name[RTE_HASH_NAMESIZE];
262 : : char sad_name[RTE_IPSEC_SAD_NAMESIZE];
263 : : struct rte_tailq_entry *te;
264 : : struct rte_ipsec_sad_list *sad_list;
265 : : struct rte_ipsec_sad *sad, *tmp_sad = NULL;
266 : 0 : struct rte_hash_parameters hash_params = {0};
267 : : int ret;
268 : : uint32_t sa_sum;
269 : :
270 : : RTE_BUILD_BUG_ON(RTE_IPSEC_SAD_KEY_TYPE_MASK != 3);
271 : :
272 [ # # ]: 0 : if ((name == NULL) || (conf == NULL) ||
273 [ # # ]: 0 : ((conf->max_sa[RTE_IPSEC_SAD_SPI_ONLY] == 0) &&
274 [ # # ]: 0 : (conf->max_sa[RTE_IPSEC_SAD_SPI_DIP] == 0) &&
275 [ # # ]: 0 : (conf->max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] == 0))) {
276 : 0 : rte_errno = EINVAL;
277 : 0 : return NULL;
278 : : }
279 : :
280 : : ret = snprintf(sad_name, RTE_IPSEC_SAD_NAMESIZE, SAD_FORMAT, name);
281 [ # # ]: 0 : if (ret < 0 || ret >= RTE_IPSEC_SAD_NAMESIZE) {
282 : 0 : rte_errno = ENAMETOOLONG;
283 : 0 : return NULL;
284 : : }
285 : :
286 : : /** Init SAD*/
287 : 0 : sa_sum = RTE_MAX(MIN_HASH_ENTRIES,
288 : 0 : conf->max_sa[RTE_IPSEC_SAD_SPI_ONLY]) +
289 : 0 : RTE_MAX(MIN_HASH_ENTRIES,
290 : : conf->max_sa[RTE_IPSEC_SAD_SPI_DIP]) +
291 : 0 : RTE_MAX(MIN_HASH_ENTRIES,
292 : : conf->max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP]);
293 : 0 : sad = rte_zmalloc_socket(NULL, sizeof(*sad) +
294 : : (sizeof(struct hash_cnt) * sa_sum),
295 : 0 : RTE_CACHE_LINE_SIZE, conf->socket_id);
296 [ # # ]: 0 : if (sad == NULL) {
297 : 0 : rte_errno = ENOMEM;
298 : 0 : return NULL;
299 : : }
300 : 0 : memcpy(sad->name, sad_name, sizeof(sad_name));
301 : :
302 : 0 : hash_params.hash_func = DEFAULT_HASH_FUNC;
303 : 0 : hash_params.hash_func_init_val = rte_rand();
304 : 0 : sad->init_val = hash_params.hash_func_init_val;
305 : 0 : hash_params.socket_id = conf->socket_id;
306 : 0 : hash_params.name = hash_name;
307 [ # # ]: 0 : if (conf->flags & RTE_IPSEC_SAD_FLAG_RW_CONCURRENCY)
308 : 0 : hash_params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY;
309 : :
310 : : /** Init hash[RTE_IPSEC_SAD_SPI_ONLY] for SPI only */
311 : : snprintf(hash_name, sizeof(hash_name), "sad_1_%p", sad);
312 : 0 : hash_params.key_len = sizeof(((struct rte_ipsec_sadv4_key *)0)->spi);
313 : 0 : sad->keysize[RTE_IPSEC_SAD_SPI_ONLY] = hash_params.key_len;
314 : 0 : hash_params.entries = sa_sum;
315 : 0 : sad->hash[RTE_IPSEC_SAD_SPI_ONLY] = rte_hash_create(&hash_params);
316 [ # # ]: 0 : if (sad->hash[RTE_IPSEC_SAD_SPI_ONLY] == NULL) {
317 : 0 : rte_ipsec_sad_destroy(sad);
318 : 0 : return NULL;
319 : : }
320 : :
321 : : /** Init hash[RTE_IPSEC_SAD_SPI_DIP] for SPI + DIP */
322 : : snprintf(hash_name, sizeof(hash_name), "sad_2_%p", sad);
323 [ # # ]: 0 : if (conf->flags & RTE_IPSEC_SAD_FLAG_IPV6)
324 : 0 : hash_params.key_len +=
325 : : sizeof(((struct rte_ipsec_sadv6_key *)0)->dip);
326 : : else
327 : 0 : hash_params.key_len +=
328 : : sizeof(((struct rte_ipsec_sadv4_key *)0)->dip);
329 : 0 : sad->keysize[RTE_IPSEC_SAD_SPI_DIP] = hash_params.key_len;
330 : 0 : hash_params.entries = RTE_MAX(MIN_HASH_ENTRIES,
331 : : conf->max_sa[RTE_IPSEC_SAD_SPI_DIP]);
332 : 0 : sad->hash[RTE_IPSEC_SAD_SPI_DIP] = rte_hash_create(&hash_params);
333 [ # # ]: 0 : if (sad->hash[RTE_IPSEC_SAD_SPI_DIP] == NULL) {
334 : 0 : rte_ipsec_sad_destroy(sad);
335 : 0 : return NULL;
336 : : }
337 : :
338 : : /** Init hash[[RTE_IPSEC_SAD_SPI_DIP_SIP] for SPI + DIP + SIP */
339 : : snprintf(hash_name, sizeof(hash_name), "sad_3_%p", sad);
340 [ # # ]: 0 : if (conf->flags & RTE_IPSEC_SAD_FLAG_IPV6)
341 : 0 : hash_params.key_len +=
342 : : sizeof(((struct rte_ipsec_sadv6_key *)0)->sip);
343 : : else
344 : 0 : hash_params.key_len +=
345 : : sizeof(((struct rte_ipsec_sadv4_key *)0)->sip);
346 : 0 : sad->keysize[RTE_IPSEC_SAD_SPI_DIP_SIP] = hash_params.key_len;
347 : 0 : hash_params.entries = RTE_MAX(MIN_HASH_ENTRIES,
348 : : conf->max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP]);
349 : 0 : sad->hash[RTE_IPSEC_SAD_SPI_DIP_SIP] = rte_hash_create(&hash_params);
350 [ # # ]: 0 : if (sad->hash[RTE_IPSEC_SAD_SPI_DIP_SIP] == NULL) {
351 : 0 : rte_ipsec_sad_destroy(sad);
352 : 0 : return NULL;
353 : : }
354 : :
355 : 0 : sad_list = RTE_TAILQ_CAST(rte_ipsec_sad_tailq.head,
356 : : rte_ipsec_sad_list);
357 : 0 : rte_mcfg_tailq_write_lock();
358 : : /* guarantee there's no existing */
359 [ # # ]: 0 : TAILQ_FOREACH(te, sad_list, next) {
360 : 0 : tmp_sad = (struct rte_ipsec_sad *)te->data;
361 [ # # ]: 0 : if (strncmp(sad_name, tmp_sad->name,
362 : : RTE_IPSEC_SAD_NAMESIZE) == 0)
363 : : break;
364 : : }
365 [ # # ]: 0 : if (te != NULL) {
366 : 0 : rte_mcfg_tailq_write_unlock();
367 : 0 : rte_errno = EEXIST;
368 : 0 : rte_ipsec_sad_destroy(sad);
369 : 0 : return NULL;
370 : : }
371 : :
372 : : /* allocate tailq entry */
373 : 0 : te = rte_zmalloc("IPSEC_SAD_TAILQ_ENTRY", sizeof(*te), 0);
374 [ # # ]: 0 : if (te == NULL) {
375 : 0 : rte_mcfg_tailq_write_unlock();
376 : 0 : rte_errno = ENOMEM;
377 : 0 : rte_ipsec_sad_destroy(sad);
378 : 0 : return NULL;
379 : : }
380 : :
381 : 0 : te->data = (void *)sad;
382 : 0 : TAILQ_INSERT_TAIL(sad_list, te, next);
383 : 0 : rte_mcfg_tailq_write_unlock();
384 : 0 : return sad;
385 : : }
386 : :
387 : : RTE_EXPORT_SYMBOL(rte_ipsec_sad_find_existing)
388 : : struct rte_ipsec_sad *
389 [ # # ]: 0 : rte_ipsec_sad_find_existing(const char *name)
390 : : {
391 : : char sad_name[RTE_IPSEC_SAD_NAMESIZE];
392 : : struct rte_ipsec_sad *sad = NULL;
393 : : struct rte_tailq_entry *te;
394 : : struct rte_ipsec_sad_list *sad_list;
395 : : int ret;
396 : :
397 : : ret = snprintf(sad_name, RTE_IPSEC_SAD_NAMESIZE, SAD_FORMAT, name);
398 [ # # ]: 0 : if (ret < 0 || ret >= RTE_IPSEC_SAD_NAMESIZE) {
399 : 0 : rte_errno = ENAMETOOLONG;
400 : 0 : return NULL;
401 : : }
402 : :
403 : 0 : sad_list = RTE_TAILQ_CAST(rte_ipsec_sad_tailq.head,
404 : : rte_ipsec_sad_list);
405 : :
406 : 0 : rte_mcfg_tailq_read_lock();
407 [ # # ]: 0 : TAILQ_FOREACH(te, sad_list, next) {
408 : 0 : sad = (struct rte_ipsec_sad *) te->data;
409 [ # # ]: 0 : if (strncmp(sad_name, sad->name, RTE_IPSEC_SAD_NAMESIZE) == 0)
410 : : break;
411 : : }
412 : 0 : rte_mcfg_tailq_read_unlock();
413 : :
414 [ # # ]: 0 : if (te == NULL) {
415 : 0 : rte_errno = ENOENT;
416 : 0 : return NULL;
417 : : }
418 : :
419 : : return sad;
420 : : }
421 : :
422 : : RTE_EXPORT_SYMBOL(rte_ipsec_sad_destroy)
423 : : void
424 : 0 : rte_ipsec_sad_destroy(struct rte_ipsec_sad *sad)
425 : : {
426 : : struct rte_tailq_entry *te;
427 : : struct rte_ipsec_sad_list *sad_list;
428 : :
429 [ # # ]: 0 : if (sad == NULL)
430 : : return;
431 : :
432 : 0 : sad_list = RTE_TAILQ_CAST(rte_ipsec_sad_tailq.head,
433 : : rte_ipsec_sad_list);
434 : 0 : rte_mcfg_tailq_write_lock();
435 [ # # ]: 0 : TAILQ_FOREACH(te, sad_list, next) {
436 [ # # ]: 0 : if (te->data == (void *)sad)
437 : : break;
438 : : }
439 [ # # ]: 0 : if (te != NULL)
440 [ # # ]: 0 : TAILQ_REMOVE(sad_list, te, next);
441 : :
442 : 0 : rte_mcfg_tailq_write_unlock();
443 : :
444 : 0 : rte_hash_free(sad->hash[RTE_IPSEC_SAD_SPI_ONLY]);
445 : 0 : rte_hash_free(sad->hash[RTE_IPSEC_SAD_SPI_DIP]);
446 : 0 : rte_hash_free(sad->hash[RTE_IPSEC_SAD_SPI_DIP_SIP]);
447 : 0 : rte_free(sad);
448 : 0 : rte_free(te);
449 : : }
450 : :
451 : : /*
452 : : * @internal helper function
453 : : * Lookup a batch of keys in three hash tables.
454 : : * First lookup key in SPI_ONLY table.
455 : : * If there is an entry for the corresponding SPI check its value.
456 : : * Two least significant bits of the value indicate
457 : : * the presence of more specific rule in other tables.
458 : : * Perform additional lookup in corresponding hash tables
459 : : * and update the value if lookup succeeded.
460 : : */
461 : : static int
462 : 0 : __ipsec_sad_lookup(const struct rte_ipsec_sad *sad,
463 : : const union rte_ipsec_sad_key *keys[], void *sa[], uint32_t n)
464 : : {
465 : : const void *keys_2[RTE_HASH_LOOKUP_BULK_MAX];
466 : : const void *keys_3[RTE_HASH_LOOKUP_BULK_MAX];
467 : 0 : void *vals_2[RTE_HASH_LOOKUP_BULK_MAX] = {NULL};
468 : 0 : void *vals_3[RTE_HASH_LOOKUP_BULK_MAX] = {NULL};
469 : : uint32_t idx_2[RTE_HASH_LOOKUP_BULK_MAX];
470 : : uint32_t idx_3[RTE_HASH_LOOKUP_BULK_MAX];
471 : : uint64_t mask_1, mask_2, mask_3;
472 : : uint64_t map, map_spec;
473 : : uint32_t n_2 = 0;
474 : : uint32_t n_3 = 0;
475 : : uint32_t i;
476 : : int found = 0;
477 : : hash_sig_t hash_sig[RTE_HASH_LOOKUP_BULK_MAX];
478 : : hash_sig_t hash_sig_2[RTE_HASH_LOOKUP_BULK_MAX];
479 : : hash_sig_t hash_sig_3[RTE_HASH_LOOKUP_BULK_MAX];
480 : :
481 [ # # ]: 0 : for (i = 0; i < n; i++) {
482 : 0 : sa[i] = NULL;
483 : 0 : hash_sig[i] = rte_hash_crc_4byte(keys[i]->v4.spi,
484 : 0 : sad->init_val);
485 : : }
486 : :
487 : : /*
488 : : * Lookup keys in SPI only hash table first.
489 : : */
490 : 0 : rte_hash_lookup_with_hash_bulk_data(sad->hash[RTE_IPSEC_SAD_SPI_ONLY],
491 : : (const void **)keys, hash_sig, n, &mask_1, sa);
492 [ # # ]: 0 : for (map = mask_1; map; map &= (map - 1)) {
493 : : i = rte_bsf64(map);
494 : : /*
495 : : * if returned value indicates presence of a rule in other
496 : : * tables save a key for further lookup.
497 : : */
498 [ # # ]: 0 : if ((uintptr_t)sa[i] & RTE_IPSEC_SAD_SPI_DIP_SIP) {
499 : 0 : idx_3[n_3] = i;
500 : 0 : hash_sig_3[n_3] = rte_hash_crc(keys[i],
501 : 0 : sad->keysize[RTE_IPSEC_SAD_SPI_DIP_SIP],
502 : 0 : sad->init_val);
503 : 0 : keys_3[n_3++] = keys[i];
504 : : }
505 [ # # ]: 0 : if ((uintptr_t)sa[i] & RTE_IPSEC_SAD_SPI_DIP) {
506 : 0 : idx_2[n_2] = i;
507 : 0 : hash_sig_2[n_2] = rte_hash_crc(keys[i],
508 : 0 : sad->keysize[RTE_IPSEC_SAD_SPI_DIP],
509 : 0 : sad->init_val);
510 : 0 : keys_2[n_2++] = keys[i];
511 : : }
512 : : /* clear 2 LSB's which indicate the presence
513 : : * of more specific rules
514 : : */
515 : 0 : sa[i] = CLEAR_BIT(sa[i], RTE_IPSEC_SAD_KEY_TYPE_MASK);
516 : : }
517 : :
518 : : /* Lookup for more specific rules in SPI_DIP table */
519 [ # # ]: 0 : if (n_2 != 0) {
520 : 0 : rte_hash_lookup_with_hash_bulk_data(
521 : 0 : sad->hash[RTE_IPSEC_SAD_SPI_DIP],
522 : : keys_2, hash_sig_2, n_2, &mask_2, vals_2);
523 [ # # ]: 0 : for (map_spec = mask_2; map_spec; map_spec &= (map_spec - 1)) {
524 : : i = rte_bsf64(map_spec);
525 : 0 : sa[idx_2[i]] = vals_2[i];
526 : : }
527 : : }
528 : : /* Lookup for more specific rules in SPI_DIP_SIP table */
529 [ # # ]: 0 : if (n_3 != 0) {
530 : 0 : rte_hash_lookup_with_hash_bulk_data(
531 : 0 : sad->hash[RTE_IPSEC_SAD_SPI_DIP_SIP],
532 : : keys_3, hash_sig_3, n_3, &mask_3, vals_3);
533 [ # # ]: 0 : for (map_spec = mask_3; map_spec; map_spec &= (map_spec - 1)) {
534 : : i = rte_bsf64(map_spec);
535 : 0 : sa[idx_3[i]] = vals_3[i];
536 : : }
537 : : }
538 : :
539 [ # # ]: 0 : for (i = 0; i < n; i++)
540 : 0 : found += (sa[i] != NULL);
541 : :
542 : 0 : return found;
543 : : }
544 : :
545 : : RTE_EXPORT_SYMBOL(rte_ipsec_sad_lookup)
546 : : int
547 : 0 : rte_ipsec_sad_lookup(const struct rte_ipsec_sad *sad,
548 : : const union rte_ipsec_sad_key *keys[], void *sa[], uint32_t n)
549 : : {
550 : : uint32_t num, i = 0;
551 : : int found = 0;
552 : :
553 [ # # # # ]: 0 : if (unlikely((sad == NULL) || (keys == NULL) || (sa == NULL)))
554 : : return -EINVAL;
555 : :
556 : : do {
557 : 0 : num = RTE_MIN(n - i, (uint32_t)RTE_HASH_LOOKUP_BULK_MAX);
558 : 0 : found += __ipsec_sad_lookup(sad,
559 : 0 : &keys[i], &sa[i], num);
560 : 0 : i += num;
561 [ # # ]: 0 : } while (i != n);
562 : :
563 : : return found;
564 : : }
|