1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2019 Intel Corporation
5 #include <rte_eal_memconfig.h>
9 #include <rte_malloc.h>
10 #include <rte_random.h>
11 #include <rte_rwlock.h>
12 #include <rte_tailq.h>
14 #include "rte_ipsec_sad.h"
17 * Rules are stored in three hash tables depending on key_type.
18 * Each rule will also be stored in SPI_ONLY table.
19 * for each data entry within this table last two bits are reserved to
20 * indicate presence of entries with the same SPI in DIP and DIP+SIP tables.
23 #define IPSEC_SAD_NAMESIZE 64
24 #define SAD_PREFIX "SAD_"
26 #define SAD_FORMAT SAD_PREFIX "%s"
28 #define DEFAULT_HASH_FUNC rte_jhash
29 #define MIN_HASH_ENTRIES 8U /* From rte_cuckoo_hash.h */
36 struct rte_ipsec_sad {
37 char name[IPSEC_SAD_NAMESIZE];
38 struct rte_hash *hash[RTE_IPSEC_SAD_KEY_TYPE_MASK];
39 /* Array to track number of more specific rules
40 * (spi_dip or spi_dip_sip). Used only in add/delete
43 __extension__ struct hash_cnt cnt_arr[];
46 TAILQ_HEAD(rte_ipsec_sad_list, rte_tailq_entry);
47 static struct rte_tailq_elem rte_ipsec_sad_tailq = {
48 .name = "RTE_IPSEC_SAD",
50 EAL_REGISTER_TAILQ(rte_ipsec_sad_tailq)
53 rte_ipsec_sad_add(__rte_unused struct rte_ipsec_sad *sad,
54 __rte_unused const union rte_ipsec_sad_key *key,
55 __rte_unused int key_type, __rte_unused void *sa)
61 rte_ipsec_sad_del(__rte_unused struct rte_ipsec_sad *sad,
62 __rte_unused const union rte_ipsec_sad_key *key,
63 __rte_unused int key_type)
68 struct rte_ipsec_sad *
69 rte_ipsec_sad_create(const char *name, const struct rte_ipsec_sad_conf *conf)
71 char hash_name[RTE_HASH_NAMESIZE];
72 char sad_name[IPSEC_SAD_NAMESIZE];
73 struct rte_tailq_entry *te;
74 struct rte_ipsec_sad_list *sad_list;
75 struct rte_ipsec_sad *sad, *tmp_sad = NULL;
76 struct rte_hash_parameters hash_params = {0};
80 RTE_BUILD_BUG_ON(RTE_IPSEC_SAD_KEY_TYPE_MASK != 3);
82 if ((name == NULL) || (conf == NULL) ||
83 ((conf->max_sa[RTE_IPSEC_SAD_SPI_ONLY] == 0) &&
84 (conf->max_sa[RTE_IPSEC_SAD_SPI_DIP] == 0) &&
85 (conf->max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] == 0))) {
90 ret = snprintf(sad_name, IPSEC_SAD_NAMESIZE, SAD_FORMAT, name);
91 if (ret < 0 || ret >= IPSEC_SAD_NAMESIZE) {
92 rte_errno = ENAMETOOLONG;
97 sa_sum = RTE_MAX(MIN_HASH_ENTRIES,
98 conf->max_sa[RTE_IPSEC_SAD_SPI_ONLY]) +
99 RTE_MAX(MIN_HASH_ENTRIES,
100 conf->max_sa[RTE_IPSEC_SAD_SPI_DIP]) +
101 RTE_MAX(MIN_HASH_ENTRIES,
102 conf->max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP]);
103 sad = rte_zmalloc_socket(NULL, sizeof(*sad) +
104 (sizeof(struct hash_cnt) * sa_sum),
105 RTE_CACHE_LINE_SIZE, conf->socket_id);
110 memcpy(sad->name, sad_name, sizeof(sad_name));
112 hash_params.hash_func = DEFAULT_HASH_FUNC;
113 hash_params.hash_func_init_val = rte_rand();
114 hash_params.socket_id = conf->socket_id;
115 hash_params.name = hash_name;
116 if (conf->flags & RTE_IPSEC_SAD_FLAG_RW_CONCURRENCY)
117 hash_params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY;
119 /** Init hash[RTE_IPSEC_SAD_SPI_ONLY] for SPI only */
120 snprintf(hash_name, sizeof(hash_name), "sad_1_%p", sad);
121 hash_params.key_len = sizeof(((struct rte_ipsec_sadv4_key *)0)->spi);
122 hash_params.entries = sa_sum;
123 sad->hash[RTE_IPSEC_SAD_SPI_ONLY] = rte_hash_create(&hash_params);
124 if (sad->hash[RTE_IPSEC_SAD_SPI_ONLY] == NULL) {
125 rte_ipsec_sad_destroy(sad);
129 /** Init hash[RTE_IPSEC_SAD_SPI_DIP] for SPI + DIP */
130 snprintf(hash_name, sizeof(hash_name), "sad_2_%p", sad);
131 if (conf->flags & RTE_IPSEC_SAD_FLAG_IPV6)
132 hash_params.key_len +=
133 sizeof(((struct rte_ipsec_sadv6_key *)0)->dip);
135 hash_params.key_len +=
136 sizeof(((struct rte_ipsec_sadv4_key *)0)->dip);
137 hash_params.entries = RTE_MAX(MIN_HASH_ENTRIES,
138 conf->max_sa[RTE_IPSEC_SAD_SPI_DIP]);
139 sad->hash[RTE_IPSEC_SAD_SPI_DIP] = rte_hash_create(&hash_params);
140 if (sad->hash[RTE_IPSEC_SAD_SPI_DIP] == NULL) {
141 rte_ipsec_sad_destroy(sad);
145 /** Init hash[[RTE_IPSEC_SAD_SPI_DIP_SIP] for SPI + DIP + SIP */
146 snprintf(hash_name, sizeof(hash_name), "sad_3_%p", sad);
147 if (conf->flags & RTE_IPSEC_SAD_FLAG_IPV6)
148 hash_params.key_len +=
149 sizeof(((struct rte_ipsec_sadv6_key *)0)->sip);
151 hash_params.key_len +=
152 sizeof(((struct rte_ipsec_sadv4_key *)0)->sip);
153 hash_params.entries = RTE_MAX(MIN_HASH_ENTRIES,
154 conf->max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP]);
155 sad->hash[RTE_IPSEC_SAD_SPI_DIP_SIP] = rte_hash_create(&hash_params);
156 if (sad->hash[RTE_IPSEC_SAD_SPI_DIP_SIP] == NULL) {
157 rte_ipsec_sad_destroy(sad);
161 sad_list = RTE_TAILQ_CAST(rte_ipsec_sad_tailq.head,
163 rte_mcfg_tailq_write_lock();
164 /* guarantee there's no existing */
165 TAILQ_FOREACH(te, sad_list, next) {
166 tmp_sad = (struct rte_ipsec_sad *)te->data;
167 if (strncmp(sad_name, tmp_sad->name, IPSEC_SAD_NAMESIZE) == 0)
171 rte_mcfg_tailq_write_unlock();
173 rte_ipsec_sad_destroy(sad);
177 /* allocate tailq entry */
178 te = rte_zmalloc("IPSEC_SAD_TAILQ_ENTRY", sizeof(*te), 0);
180 rte_mcfg_tailq_write_unlock();
182 rte_ipsec_sad_destroy(sad);
186 te->data = (void *)sad;
187 TAILQ_INSERT_TAIL(sad_list, te, next);
188 rte_mcfg_tailq_write_unlock();
192 struct rte_ipsec_sad *
193 rte_ipsec_sad_find_existing(const char *name)
195 char sad_name[IPSEC_SAD_NAMESIZE];
196 struct rte_ipsec_sad *sad = NULL;
197 struct rte_tailq_entry *te;
198 struct rte_ipsec_sad_list *sad_list;
201 ret = snprintf(sad_name, IPSEC_SAD_NAMESIZE, SAD_FORMAT, name);
202 if (ret < 0 || ret >= IPSEC_SAD_NAMESIZE) {
203 rte_errno = ENAMETOOLONG;
207 sad_list = RTE_TAILQ_CAST(rte_ipsec_sad_tailq.head,
210 rte_mcfg_tailq_read_lock();
211 TAILQ_FOREACH(te, sad_list, next) {
212 sad = (struct rte_ipsec_sad *) te->data;
213 if (strncmp(sad_name, sad->name, IPSEC_SAD_NAMESIZE) == 0)
216 rte_mcfg_tailq_read_unlock();
227 rte_ipsec_sad_destroy(struct rte_ipsec_sad *sad)
229 struct rte_tailq_entry *te;
230 struct rte_ipsec_sad_list *sad_list;
235 sad_list = RTE_TAILQ_CAST(rte_ipsec_sad_tailq.head,
237 rte_mcfg_tailq_write_lock();
238 TAILQ_FOREACH(te, sad_list, next) {
239 if (te->data == (void *)sad)
243 TAILQ_REMOVE(sad_list, te, next);
245 rte_mcfg_tailq_write_unlock();
247 rte_hash_free(sad->hash[RTE_IPSEC_SAD_SPI_ONLY]);
248 rte_hash_free(sad->hash[RTE_IPSEC_SAD_SPI_DIP]);
249 rte_hash_free(sad->hash[RTE_IPSEC_SAD_SPI_DIP_SIP]);
256 rte_ipsec_sad_lookup(__rte_unused const struct rte_ipsec_sad *sad,
257 __rte_unused const union rte_ipsec_sad_key *keys[],
258 __rte_unused void *sa[], __rte_unused uint32_t n)