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 <netinet/ip.h>
39 #include <rte_memzone.h>
40 #include <rte_crypto.h>
41 #include <rte_cryptodev.h>
42 #include <rte_byteorder.h>
43 #include <rte_errno.h>
48 /* SAs EP0 Outbound */
49 const struct ipsec_sa sa_ep0_out[] = {
50 { 5, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5),
52 esp4_tunnel_outbound_pre_crypto,
53 esp4_tunnel_outbound_post_crypto,
54 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
57 { 6, 0, IPv4(172, 16, 1, 6), IPv4(172, 16, 2, 6),
59 esp4_tunnel_outbound_pre_crypto,
60 esp4_tunnel_outbound_post_crypto,
61 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
64 { 7, 0, IPv4(172, 16, 1, 7), IPv4(172, 16, 2, 7),
66 esp4_tunnel_outbound_pre_crypto,
67 esp4_tunnel_outbound_post_crypto,
68 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
71 { 8, 0, IPv4(172, 16, 1, 8), IPv4(172, 16, 2, 8),
73 esp4_tunnel_outbound_pre_crypto,
74 esp4_tunnel_outbound_post_crypto,
75 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
78 { 9, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5),
80 esp4_tunnel_outbound_pre_crypto,
81 esp4_tunnel_outbound_post_crypto,
82 RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL,
88 const struct ipsec_sa sa_ep0_in[] = {
89 { 5, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5),
91 esp4_tunnel_inbound_pre_crypto,
92 esp4_tunnel_inbound_post_crypto,
93 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
96 { 6, 0, IPv4(172, 16, 2, 6), IPv4(172, 16, 1, 6),
98 esp4_tunnel_inbound_pre_crypto,
99 esp4_tunnel_inbound_post_crypto,
100 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
103 { 7, 0, IPv4(172, 16, 2, 7), IPv4(172, 16, 1, 7),
105 esp4_tunnel_inbound_pre_crypto,
106 esp4_tunnel_inbound_post_crypto,
107 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
110 { 8, 0, IPv4(172, 16, 2, 8), IPv4(172, 16, 1, 8),
112 esp4_tunnel_inbound_pre_crypto,
113 esp4_tunnel_inbound_post_crypto,
114 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
117 { 9, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5),
119 esp4_tunnel_inbound_pre_crypto,
120 esp4_tunnel_inbound_post_crypto,
121 RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL,
126 /* SAs EP1 Outbound */
127 const struct ipsec_sa sa_ep1_out[] = {
128 { 5, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5),
130 esp4_tunnel_outbound_pre_crypto,
131 esp4_tunnel_outbound_post_crypto,
132 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
135 { 6, 0, IPv4(172, 16, 2, 6), IPv4(172, 16, 1, 6),
137 esp4_tunnel_outbound_pre_crypto,
138 esp4_tunnel_outbound_post_crypto,
139 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
142 { 7, 0, IPv4(172, 16, 2, 7), IPv4(172, 16, 1, 7),
144 esp4_tunnel_outbound_pre_crypto,
145 esp4_tunnel_outbound_post_crypto,
146 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
149 { 8, 0, IPv4(172, 16, 2, 8), IPv4(172, 16, 1, 8),
151 esp4_tunnel_outbound_pre_crypto,
152 esp4_tunnel_outbound_post_crypto,
153 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
156 { 9, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5),
158 esp4_tunnel_outbound_pre_crypto,
159 esp4_tunnel_outbound_post_crypto,
160 RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL,
165 /* SAs EP1 Inbound */
166 const struct ipsec_sa sa_ep1_in[] = {
167 { 5, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5),
169 esp4_tunnel_inbound_pre_crypto,
170 esp4_tunnel_inbound_post_crypto,
171 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
174 { 6, 0, IPv4(172, 16, 1, 6), IPv4(172, 16, 2, 6),
176 esp4_tunnel_inbound_pre_crypto,
177 esp4_tunnel_inbound_post_crypto,
178 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
181 { 7, 0, IPv4(172, 16, 1, 7), IPv4(172, 16, 2, 7),
183 esp4_tunnel_inbound_pre_crypto,
184 esp4_tunnel_inbound_post_crypto,
185 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
188 { 8, 0, IPv4(172, 16, 1, 8), IPv4(172, 16, 2, 8),
190 esp4_tunnel_inbound_pre_crypto,
191 esp4_tunnel_inbound_post_crypto,
192 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
195 { 9, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5),
197 esp4_tunnel_inbound_pre_crypto,
198 esp4_tunnel_inbound_post_crypto,
199 RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL,
204 static uint8_t cipher_key[256] = "sixteenbytes key";
207 const struct rte_crypto_sym_xform aescbc_enc_xf = {
209 RTE_CRYPTO_SYM_XFORM_CIPHER,
210 .cipher = { RTE_CRYPTO_CIPHER_OP_ENCRYPT, RTE_CRYPTO_CIPHER_AES_CBC,
211 .key = { cipher_key, 16 } }
214 const struct rte_crypto_sym_xform aescbc_dec_xf = {
216 RTE_CRYPTO_SYM_XFORM_CIPHER,
217 .cipher = { RTE_CRYPTO_CIPHER_OP_DECRYPT, RTE_CRYPTO_CIPHER_AES_CBC,
218 .key = { cipher_key, 16 } }
221 static uint8_t auth_key[256] = "twentybytes hash key";
223 /* SHA1 HMAC xform */
224 const struct rte_crypto_sym_xform sha1hmac_gen_xf = {
226 RTE_CRYPTO_SYM_XFORM_AUTH,
227 .auth = { RTE_CRYPTO_AUTH_OP_GENERATE, RTE_CRYPTO_AUTH_SHA1_HMAC,
228 .key = { auth_key, 20 }, 12, 0 }
231 const struct rte_crypto_sym_xform sha1hmac_verify_xf = {
233 RTE_CRYPTO_SYM_XFORM_AUTH,
234 .auth = { RTE_CRYPTO_AUTH_OP_VERIFY, RTE_CRYPTO_AUTH_SHA1_HMAC,
235 .key = { auth_key, 20 }, 12, 0 }
239 const struct rte_crypto_sym_xform null_cipher_xf = {
241 RTE_CRYPTO_SYM_XFORM_CIPHER,
242 .cipher = { .algo = RTE_CRYPTO_CIPHER_NULL }
245 const struct rte_crypto_sym_xform null_auth_xf = {
247 RTE_CRYPTO_SYM_XFORM_AUTH,
248 .auth = { .algo = RTE_CRYPTO_AUTH_NULL }
252 struct ipsec_sa sa[IPSEC_SA_MAX_ENTRIES];
254 struct rte_crypto_sym_xform a;
255 struct rte_crypto_sym_xform b;
256 } xf[IPSEC_SA_MAX_ENTRIES];
259 static struct sa_ctx *
260 sa_ipv4_create(const char *name, int socket_id)
263 struct sa_ctx *sa_ctx;
265 const struct rte_memzone *mz;
267 snprintf(s, sizeof(s), "%s_%u", name, socket_id);
269 /* Create SA array table */
270 printf("Creating SA context with %u maximum entries\n",
271 IPSEC_SA_MAX_ENTRIES);
273 mz_size = sizeof(struct sa_ctx);
274 mz = rte_memzone_reserve(s, mz_size, socket_id,
275 RTE_MEMZONE_1GB | RTE_MEMZONE_SIZE_HINT_ONLY);
277 printf("Failed to allocate SA DB memory\n");
282 sa_ctx = (struct sa_ctx *)mz->addr;
288 sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
289 unsigned nb_entries, unsigned inbound)
294 for (i = 0; i < nb_entries; i++) {
295 idx = SPI2IDX(entries[i].spi);
296 sa = &sa_ctx->sa[idx];
298 printf("Index %u already in use by SPI %u\n",
303 sa->src = rte_cpu_to_be_32(sa->src);
304 sa->dst = rte_cpu_to_be_32(sa->dst);
306 if (sa->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
307 sa_ctx->xf[idx].a = null_auth_xf;
308 sa_ctx->xf[idx].b = null_cipher_xf;
310 sa_ctx->xf[idx].a = sha1hmac_verify_xf;
311 sa_ctx->xf[idx].b = aescbc_dec_xf;
313 } else { /* outbound */
314 if (sa->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
315 sa_ctx->xf[idx].a = null_cipher_xf;
316 sa_ctx->xf[idx].b = null_auth_xf;
318 sa_ctx->xf[idx].a = aescbc_enc_xf;
319 sa_ctx->xf[idx].b = sha1hmac_gen_xf;
322 sa_ctx->xf[idx].a.next = &sa_ctx->xf[idx].b;
323 sa_ctx->xf[idx].b.next = NULL;
324 sa->xforms = &sa_ctx->xf[idx].a;
331 sa_out_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
334 return sa_add_rules(sa_ctx, entries, nb_entries, 0);
338 sa_in_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
341 return sa_add_rules(sa_ctx, entries, nb_entries, 1);
345 sa_init(struct socket_ctx *ctx, int socket_id, unsigned ep)
347 const struct ipsec_sa *sa_out_entries, *sa_in_entries;
348 unsigned nb_out_entries, nb_in_entries;
352 rte_exit(EXIT_FAILURE, "NULL context.\n");
354 if (ctx->sa_ipv4_in != NULL)
355 rte_exit(EXIT_FAILURE, "Inbound SA DB for socket %u already "
356 "initialized\n", socket_id);
358 if (ctx->sa_ipv4_out != NULL)
359 rte_exit(EXIT_FAILURE, "Outbound SA DB for socket %u already "
360 "initialized\n", socket_id);
363 sa_out_entries = sa_ep0_out;
364 nb_out_entries = RTE_DIM(sa_ep0_out);
365 sa_in_entries = sa_ep0_in;
366 nb_in_entries = RTE_DIM(sa_ep0_in);
367 } else if (ep == 1) {
368 sa_out_entries = sa_ep1_out;
369 nb_out_entries = RTE_DIM(sa_ep1_out);
370 sa_in_entries = sa_ep1_in;
371 nb_in_entries = RTE_DIM(sa_ep1_in);
373 rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
374 "Only 0 or 1 supported.\n", ep);
377 ctx->sa_ipv4_in = sa_ipv4_create(name, socket_id);
378 if (ctx->sa_ipv4_in == NULL)
379 rte_exit(EXIT_FAILURE, "Error [%d] creating SA context %s "
380 "in socket %d\n", rte_errno, name, socket_id);
382 name = "sa_ipv4_out";
383 ctx->sa_ipv4_out = sa_ipv4_create(name, socket_id);
384 if (ctx->sa_ipv4_out == NULL)
385 rte_exit(EXIT_FAILURE, "Error [%d] creating SA context %s "
386 "in socket %d\n", rte_errno, name, socket_id);
388 sa_in_add_rules(ctx->sa_ipv4_in, sa_in_entries, nb_in_entries);
390 sa_out_add_rules(ctx->sa_ipv4_out, sa_out_entries, nb_out_entries);
394 inbound_sa_check(struct sa_ctx *sa_ctx, struct rte_mbuf *m, uint32_t sa_idx)
396 struct ipsec_mbuf_metadata *priv;
398 priv = RTE_PTR_ADD(m, sizeof(struct rte_mbuf));
400 return (sa_ctx->sa[sa_idx].spi == priv->sa->spi);
404 inbound_sa_lookup(struct sa_ctx *sa_ctx, struct rte_mbuf *pkts[],
405 struct ipsec_sa *sa[], uint16_t nb_pkts)
410 for (i = 0; i < nb_pkts; i++) {
411 spi = rte_pktmbuf_mtod_offset(pkts[i], struct esp_hdr *,
412 sizeof(struct ip))->spi;
414 if (spi == INVALID_SPI)
417 sa[i] = &sa_ctx->sa[SPI2IDX(spi)];
418 if (spi != sa[i]->spi) {
423 src = rte_pktmbuf_mtod_offset(pkts[i], uint32_t *,
424 offsetof(struct ip, ip_src));
425 if ((sa[i]->src != *src) || (sa[i]->dst != *(src + 1)))
431 outbound_sa_lookup(struct sa_ctx *sa_ctx, uint32_t sa_idx[],
432 struct ipsec_sa *sa[], uint16_t nb_pkts)
436 for (i = 0; i < nb_pkts; i++)
437 sa[i] = &sa_ctx->sa[sa_idx[i]];