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>
40 #include <netinet/ip6.h>
42 #include <rte_memzone.h>
43 #include <rte_crypto.h>
44 #include <rte_cryptodev.h>
45 #include <rte_byteorder.h>
46 #include <rte_errno.h>
53 const struct ipsec_sa sa_out[] = {
56 .src.ip.ip4 = IPv4(172, 16, 1, 5),
57 .dst.ip.ip4 = IPv4(172, 16, 2, 5),
58 .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
59 .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
67 .src.ip.ip4 = IPv4(172, 16, 1, 6),
68 .dst.ip.ip4 = IPv4(172, 16, 2, 6),
69 .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
70 .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
78 .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
79 .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
87 .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
88 .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
96 .src.ip.ip4 = IPv4(172, 16, 1, 5),
97 .dst.ip.ip4 = IPv4(172, 16, 2, 5),
98 .cipher_algo = RTE_CRYPTO_CIPHER_NULL,
99 .auth_algo = RTE_CRYPTO_AUTH_NULL,
107 .src.ip.ip4 = IPv4(172, 16, 1, 6),
108 .dst.ip.ip4 = IPv4(172, 16, 2, 6),
109 .cipher_algo = RTE_CRYPTO_CIPHER_NULL,
110 .auth_algo = RTE_CRYPTO_AUTH_NULL,
118 .src.ip.ip6.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
119 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x55, 0x55 },
120 .dst.ip.ip6.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
121 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x55, 0x55 },
122 .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
123 .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
131 .src.ip.ip6.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
132 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x66, 0x66 },
133 .dst.ip.ip6.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
134 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x66, 0x66 },
135 .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
136 .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
145 const struct ipsec_sa sa_in[] = {
148 .src.ip.ip4 = IPv4(172, 16, 2, 5),
149 .dst.ip.ip4 = IPv4(172, 16, 1, 5),
150 .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
151 .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
159 .src.ip.ip4 = IPv4(172, 16, 2, 6),
160 .dst.ip.ip4 = IPv4(172, 16, 1, 6),
161 .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
162 .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
170 .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
171 .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
179 .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
180 .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
188 .src.ip.ip4 = IPv4(172, 16, 2, 5),
189 .dst.ip.ip4 = IPv4(172, 16, 1, 5),
190 .cipher_algo = RTE_CRYPTO_CIPHER_NULL,
191 .auth_algo = RTE_CRYPTO_AUTH_NULL,
199 .src.ip.ip4 = IPv4(172, 16, 2, 6),
200 .dst.ip.ip4 = IPv4(172, 16, 1, 6),
201 .cipher_algo = RTE_CRYPTO_CIPHER_NULL,
202 .auth_algo = RTE_CRYPTO_AUTH_NULL,
210 .src.ip.ip6.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
211 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x55, 0x55 },
212 .dst.ip.ip6.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
213 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x55, 0x55 },
214 .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
215 .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
223 .src.ip.ip6.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
224 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x66, 0x66 },
225 .dst.ip.ip6.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
226 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x66, 0x66 },
227 .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
228 .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
236 static uint8_t cipher_key[256] = "sixteenbytes key";
239 const struct rte_crypto_sym_xform aescbc_enc_xf = {
241 RTE_CRYPTO_SYM_XFORM_CIPHER,
242 {.cipher = { RTE_CRYPTO_CIPHER_OP_ENCRYPT, RTE_CRYPTO_CIPHER_AES_CBC,
243 .key = { cipher_key, 16 } }
247 const struct rte_crypto_sym_xform aescbc_dec_xf = {
249 RTE_CRYPTO_SYM_XFORM_CIPHER,
250 {.cipher = { RTE_CRYPTO_CIPHER_OP_DECRYPT, RTE_CRYPTO_CIPHER_AES_CBC,
251 .key = { cipher_key, 16 } }
255 static uint8_t auth_key[256] = "twentybytes hash key";
257 /* SHA1 HMAC xform */
258 const struct rte_crypto_sym_xform sha1hmac_gen_xf = {
260 RTE_CRYPTO_SYM_XFORM_AUTH,
261 {.auth = { RTE_CRYPTO_AUTH_OP_GENERATE, RTE_CRYPTO_AUTH_SHA1_HMAC,
262 .key = { auth_key, 20 }, 12, 0 }
266 const struct rte_crypto_sym_xform sha1hmac_verify_xf = {
268 RTE_CRYPTO_SYM_XFORM_AUTH,
269 {.auth = { RTE_CRYPTO_AUTH_OP_VERIFY, RTE_CRYPTO_AUTH_SHA1_HMAC,
270 .key = { auth_key, 20 }, 12, 0 }
275 const struct rte_crypto_sym_xform null_cipher_xf = {
277 RTE_CRYPTO_SYM_XFORM_CIPHER,
278 {.cipher = { .algo = RTE_CRYPTO_CIPHER_NULL }
282 const struct rte_crypto_sym_xform null_auth_xf = {
284 RTE_CRYPTO_SYM_XFORM_AUTH,
285 {.auth = { .algo = RTE_CRYPTO_AUTH_NULL }
290 struct ipsec_sa sa[IPSEC_SA_MAX_ENTRIES];
292 struct rte_crypto_sym_xform a;
293 struct rte_crypto_sym_xform b;
294 } xf[IPSEC_SA_MAX_ENTRIES];
297 static struct sa_ctx *
298 sa_create(const char *name, int32_t socket_id)
301 struct sa_ctx *sa_ctx;
303 const struct rte_memzone *mz;
305 snprintf(s, sizeof(s), "%s_%u", name, socket_id);
307 /* Create SA array table */
308 printf("Creating SA context with %u maximum entries\n",
309 IPSEC_SA_MAX_ENTRIES);
311 mz_size = sizeof(struct sa_ctx);
312 mz = rte_memzone_reserve(s, mz_size, socket_id,
313 RTE_MEMZONE_1GB | RTE_MEMZONE_SIZE_HINT_ONLY);
315 printf("Failed to allocate SA DB memory\n");
320 sa_ctx = (struct sa_ctx *)mz->addr;
326 sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
327 uint32_t nb_entries, uint32_t inbound)
332 for (i = 0; i < nb_entries; i++) {
333 idx = SPI2IDX(entries[i].spi);
334 sa = &sa_ctx->sa[idx];
336 printf("Index %u already in use by SPI %u\n",
345 sa->src.ip.ip4 = rte_cpu_to_be_32(sa->src.ip.ip4);
346 sa->dst.ip.ip4 = rte_cpu_to_be_32(sa->dst.ip.ip4);
350 if (sa->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
351 sa_ctx->xf[idx].a = null_auth_xf;
352 sa_ctx->xf[idx].b = null_cipher_xf;
354 sa_ctx->xf[idx].a = sha1hmac_verify_xf;
355 sa_ctx->xf[idx].b = aescbc_dec_xf;
357 } else { /* outbound */
358 if (sa->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
359 sa_ctx->xf[idx].a = null_cipher_xf;
360 sa_ctx->xf[idx].b = null_auth_xf;
362 sa_ctx->xf[idx].a = aescbc_enc_xf;
363 sa_ctx->xf[idx].b = sha1hmac_gen_xf;
366 sa_ctx->xf[idx].a.next = &sa_ctx->xf[idx].b;
367 sa_ctx->xf[idx].b.next = NULL;
368 sa->xforms = &sa_ctx->xf[idx].a;
375 sa_out_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
378 return sa_add_rules(sa_ctx, entries, nb_entries, 0);
382 sa_in_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
385 return sa_add_rules(sa_ctx, entries, nb_entries, 1);
389 sa_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)
391 const struct ipsec_sa *sa_out_entries, *sa_in_entries;
392 uint32_t nb_out_entries, nb_in_entries;
396 rte_exit(EXIT_FAILURE, "NULL context.\n");
398 if (ctx->sa_in != NULL)
399 rte_exit(EXIT_FAILURE, "Inbound SA DB for socket %u already "
400 "initialized\n", socket_id);
402 if (ctx->sa_out != NULL)
403 rte_exit(EXIT_FAILURE, "Outbound SA DB for socket %u already "
404 "initialized\n", socket_id);
407 sa_out_entries = sa_out;
408 nb_out_entries = RTE_DIM(sa_out);
409 sa_in_entries = sa_in;
410 nb_in_entries = RTE_DIM(sa_in);
411 } else if (ep == 1) {
412 sa_out_entries = sa_in;
413 nb_out_entries = RTE_DIM(sa_in);
414 sa_in_entries = sa_out;
415 nb_in_entries = RTE_DIM(sa_out);
417 rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
418 "Only 0 or 1 supported.\n", ep);
421 ctx->sa_in = sa_create(name, socket_id);
422 if (ctx->sa_in == NULL)
423 rte_exit(EXIT_FAILURE, "Error [%d] creating SA context %s "
424 "in socket %d\n", rte_errno, name, socket_id);
427 ctx->sa_out = sa_create(name, socket_id);
428 if (ctx->sa_out == NULL)
429 rte_exit(EXIT_FAILURE, "Error [%d] creating SA context %s "
430 "in socket %d\n", rte_errno, name, socket_id);
432 sa_in_add_rules(ctx->sa_in, sa_in_entries, nb_in_entries);
434 sa_out_add_rules(ctx->sa_out, sa_out_entries, nb_out_entries);
438 inbound_sa_check(struct sa_ctx *sa_ctx, struct rte_mbuf *m, uint32_t sa_idx)
440 struct ipsec_mbuf_metadata *priv;
442 priv = RTE_PTR_ADD(m, sizeof(struct rte_mbuf));
444 return (sa_ctx->sa[sa_idx].spi == priv->sa->spi);
448 single_inbound_lookup(struct ipsec_sa *sadb, struct rte_mbuf *pkt,
449 struct ipsec_sa **sa_ret)
459 ip = rte_pktmbuf_mtod(pkt, struct ip *);
460 if (ip->ip_v == IPVERSION)
461 esp = (struct esp_hdr *)(ip + 1);
463 esp = (struct esp_hdr *)(((struct ip6_hdr *)ip) + 1);
465 if (esp->spi == INVALID_SPI)
468 sa = &sadb[SPI2IDX(rte_be_to_cpu_32(esp->spi))];
469 if (rte_be_to_cpu_32(esp->spi) != sa->spi)
474 src4_addr = RTE_PTR_ADD(ip, offsetof(struct ip, ip_src));
475 if ((ip->ip_v == IPVERSION) &&
476 (sa->src.ip.ip4 == *src4_addr) &&
477 (sa->dst.ip.ip4 == *(src4_addr + 1)))
481 src6_addr = RTE_PTR_ADD(ip, offsetof(struct ip6_hdr, ip6_src));
482 if ((ip->ip_v == IP6_VERSION) &&
483 !memcmp(&sa->src.ip.ip6.ip6, src6_addr, 16) &&
484 !memcmp(&sa->dst.ip.ip6.ip6, src6_addr + 16, 16))
493 inbound_sa_lookup(struct sa_ctx *sa_ctx, struct rte_mbuf *pkts[],
494 struct ipsec_sa *sa[], uint16_t nb_pkts)
498 for (i = 0; i < nb_pkts; i++)
499 single_inbound_lookup(sa_ctx->sa, pkts[i], &sa[i]);
503 outbound_sa_lookup(struct sa_ctx *sa_ctx, uint32_t sa_idx[],
504 struct ipsec_sa *sa[], uint16_t nb_pkts)
508 for (i = 0; i < nb_pkts; i++)
509 sa[i] = &sa_ctx->sa[sa_idx[i]];