4 * Copyright(c) 2016 Intel Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 * Security Associations
37 #include <sys/types.h>
38 #include <netinet/in.h>
39 #include <netinet/ip.h>
41 #include <rte_memzone.h>
42 #include <rte_crypto.h>
43 #include <rte_cryptodev.h>
44 #include <rte_byteorder.h>
45 #include <rte_errno.h>
51 const struct ipsec_sa sa_out[] = {
54 .src = IPv4(172, 16, 1, 5),
55 .dst = IPv4(172, 16, 2, 5),
56 .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
57 .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
64 .src = IPv4(172, 16, 1, 6),
65 .dst = IPv4(172, 16, 2, 6),
66 .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
67 .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
74 .src = IPv4(172, 16, 1, 7),
75 .dst = IPv4(172, 16, 2, 7),
76 .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
77 .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
84 .src = IPv4(172, 16, 1, 8),
85 .dst = IPv4(172, 16, 2, 8),
86 .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
87 .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
94 .src = IPv4(172, 16, 1, 9),
95 .dst = IPv4(172, 16, 2, 9),
96 .cipher_algo = RTE_CRYPTO_CIPHER_NULL,
97 .auth_algo = RTE_CRYPTO_AUTH_NULL,
105 const struct ipsec_sa sa_in[] = {
108 .src = IPv4(172, 16, 2, 5),
109 .dst = IPv4(172, 16, 1, 5),
110 .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
111 .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
118 .src = IPv4(172, 16, 2, 6),
119 .dst = IPv4(172, 16, 1, 6),
120 .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
121 .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
128 .src = IPv4(172, 16, 2, 7),
129 .dst = IPv4(172, 16, 1, 7),
130 .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
131 .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
138 .src = IPv4(172, 16, 2, 8),
139 .dst = IPv4(172, 16, 1, 8),
140 .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
141 .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
148 .src = IPv4(172, 16, 2, 9),
149 .dst = IPv4(172, 16, 1, 9),
150 .cipher_algo = RTE_CRYPTO_CIPHER_NULL,
151 .auth_algo = RTE_CRYPTO_AUTH_NULL,
158 static uint8_t cipher_key[256] = "sixteenbytes key";
161 const struct rte_crypto_sym_xform aescbc_enc_xf = {
163 RTE_CRYPTO_SYM_XFORM_CIPHER,
164 {.cipher = { RTE_CRYPTO_CIPHER_OP_ENCRYPT, RTE_CRYPTO_CIPHER_AES_CBC,
165 .key = { cipher_key, 16 } }
169 const struct rte_crypto_sym_xform aescbc_dec_xf = {
171 RTE_CRYPTO_SYM_XFORM_CIPHER,
172 {.cipher = { RTE_CRYPTO_CIPHER_OP_DECRYPT, RTE_CRYPTO_CIPHER_AES_CBC,
173 .key = { cipher_key, 16 } }
177 static uint8_t auth_key[256] = "twentybytes hash key";
179 /* SHA1 HMAC xform */
180 const struct rte_crypto_sym_xform sha1hmac_gen_xf = {
182 RTE_CRYPTO_SYM_XFORM_AUTH,
183 {.auth = { RTE_CRYPTO_AUTH_OP_GENERATE, RTE_CRYPTO_AUTH_SHA1_HMAC,
184 .key = { auth_key, 20 }, 12, 0 }
188 const struct rte_crypto_sym_xform sha1hmac_verify_xf = {
190 RTE_CRYPTO_SYM_XFORM_AUTH,
191 {.auth = { RTE_CRYPTO_AUTH_OP_VERIFY, RTE_CRYPTO_AUTH_SHA1_HMAC,
192 .key = { auth_key, 20 }, 12, 0 }
197 const struct rte_crypto_sym_xform null_cipher_xf = {
199 RTE_CRYPTO_SYM_XFORM_CIPHER,
200 {.cipher = { .algo = RTE_CRYPTO_CIPHER_NULL }
204 const struct rte_crypto_sym_xform null_auth_xf = {
206 RTE_CRYPTO_SYM_XFORM_AUTH,
207 {.auth = { .algo = RTE_CRYPTO_AUTH_NULL }
212 struct ipsec_sa sa[IPSEC_SA_MAX_ENTRIES];
214 struct rte_crypto_sym_xform a;
215 struct rte_crypto_sym_xform b;
216 } xf[IPSEC_SA_MAX_ENTRIES];
219 static struct sa_ctx *
220 sa_ipv4_create(const char *name, int socket_id)
223 struct sa_ctx *sa_ctx;
225 const struct rte_memzone *mz;
227 snprintf(s, sizeof(s), "%s_%u", name, socket_id);
229 /* Create SA array table */
230 printf("Creating SA context with %u maximum entries\n",
231 IPSEC_SA_MAX_ENTRIES);
233 mz_size = sizeof(struct sa_ctx);
234 mz = rte_memzone_reserve(s, mz_size, socket_id,
235 RTE_MEMZONE_1GB | RTE_MEMZONE_SIZE_HINT_ONLY);
237 printf("Failed to allocate SA DB memory\n");
242 sa_ctx = (struct sa_ctx *)mz->addr;
248 sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
249 unsigned nb_entries, unsigned inbound)
254 for (i = 0; i < nb_entries; i++) {
255 idx = SPI2IDX(entries[i].spi);
256 sa = &sa_ctx->sa[idx];
258 printf("Index %u already in use by SPI %u\n",
263 sa->src = rte_cpu_to_be_32(sa->src);
264 sa->dst = rte_cpu_to_be_32(sa->dst);
266 if (sa->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
267 sa_ctx->xf[idx].a = null_auth_xf;
268 sa_ctx->xf[idx].b = null_cipher_xf;
270 sa_ctx->xf[idx].a = sha1hmac_verify_xf;
271 sa_ctx->xf[idx].b = aescbc_dec_xf;
273 } else { /* outbound */
274 if (sa->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
275 sa_ctx->xf[idx].a = null_cipher_xf;
276 sa_ctx->xf[idx].b = null_auth_xf;
278 sa_ctx->xf[idx].a = aescbc_enc_xf;
279 sa_ctx->xf[idx].b = sha1hmac_gen_xf;
282 sa_ctx->xf[idx].a.next = &sa_ctx->xf[idx].b;
283 sa_ctx->xf[idx].b.next = NULL;
284 sa->xforms = &sa_ctx->xf[idx].a;
291 sa_out_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
294 return sa_add_rules(sa_ctx, entries, nb_entries, 0);
298 sa_in_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
301 return sa_add_rules(sa_ctx, entries, nb_entries, 1);
305 sa_init(struct socket_ctx *ctx, int socket_id, unsigned ep)
307 const struct ipsec_sa *sa_out_entries, *sa_in_entries;
308 unsigned nb_out_entries, nb_in_entries;
312 rte_exit(EXIT_FAILURE, "NULL context.\n");
314 if (ctx->sa_ipv4_in != NULL)
315 rte_exit(EXIT_FAILURE, "Inbound SA DB for socket %u already "
316 "initialized\n", socket_id);
318 if (ctx->sa_ipv4_out != NULL)
319 rte_exit(EXIT_FAILURE, "Outbound SA DB for socket %u already "
320 "initialized\n", socket_id);
323 sa_out_entries = sa_out;
324 nb_out_entries = RTE_DIM(sa_out);
325 sa_in_entries = sa_in;
326 nb_in_entries = RTE_DIM(sa_in);
327 } else if (ep == 1) {
328 sa_out_entries = sa_in;
329 nb_out_entries = RTE_DIM(sa_in);
330 sa_in_entries = sa_out;
331 nb_in_entries = RTE_DIM(sa_out);
333 rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
334 "Only 0 or 1 supported.\n", ep);
337 ctx->sa_ipv4_in = sa_ipv4_create(name, socket_id);
338 if (ctx->sa_ipv4_in == NULL)
339 rte_exit(EXIT_FAILURE, "Error [%d] creating SA context %s "
340 "in socket %d\n", rte_errno, name, socket_id);
342 name = "sa_ipv4_out";
343 ctx->sa_ipv4_out = sa_ipv4_create(name, socket_id);
344 if (ctx->sa_ipv4_out == NULL)
345 rte_exit(EXIT_FAILURE, "Error [%d] creating SA context %s "
346 "in socket %d\n", rte_errno, name, socket_id);
348 sa_in_add_rules(ctx->sa_ipv4_in, sa_in_entries, nb_in_entries);
350 sa_out_add_rules(ctx->sa_ipv4_out, sa_out_entries, nb_out_entries);
354 inbound_sa_check(struct sa_ctx *sa_ctx, struct rte_mbuf *m, uint32_t sa_idx)
356 struct ipsec_mbuf_metadata *priv;
358 priv = RTE_PTR_ADD(m, sizeof(struct rte_mbuf));
360 return (sa_ctx->sa[sa_idx].spi == priv->sa->spi);
364 inbound_sa_lookup(struct sa_ctx *sa_ctx, struct rte_mbuf *pkts[],
365 struct ipsec_sa *sa[], uint16_t nb_pkts)
370 for (i = 0; i < nb_pkts; i++) {
371 spi = rte_pktmbuf_mtod_offset(pkts[i], struct esp_hdr *,
372 sizeof(struct ip))->spi;
374 if (spi == INVALID_SPI)
377 sa[i] = &sa_ctx->sa[SPI2IDX(spi)];
378 if (spi != sa[i]->spi) {
383 src = rte_pktmbuf_mtod_offset(pkts[i], uint32_t *,
384 offsetof(struct ip, ip_src));
385 if ((sa[i]->src != *src) || (sa[i]->dst != *(src + 1)))
391 outbound_sa_lookup(struct sa_ctx *sa_ctx, uint32_t sa_idx[],
392 struct ipsec_sa *sa[], uint16_t nb_pkts)
396 for (i = 0; i < nb_pkts; i++)
397 sa[i] = &sa_ctx->sa[sa_idx[i]];