cryptodev: move IV parameters to session
[dpdk.git] / examples / ipsec-secgw / sa.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2016 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
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
16  *       distribution.
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.
20  *
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.
32  */
33
34 /*
35  * Security Associations
36  */
37 #include <sys/types.h>
38 #include <netinet/in.h>
39 #include <netinet/ip.h>
40 #include <netinet/ip6.h>
41
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>
47 #include <rte_ip.h>
48 #include <rte_random.h>
49
50 #include "ipsec.h"
51 #include "esp.h"
52 #include "parser.h"
53
54 struct supported_cipher_algo {
55         const char *keyword;
56         enum rte_crypto_cipher_algorithm algo;
57         uint16_t iv_len;
58         uint16_t block_size;
59         uint16_t key_len;
60 };
61
62 struct supported_auth_algo {
63         const char *keyword;
64         enum rte_crypto_auth_algorithm algo;
65         uint16_t digest_len;
66         uint16_t key_len;
67         uint8_t aad_len;
68         uint8_t key_not_req;
69 };
70
71 const struct supported_cipher_algo cipher_algos[] = {
72         {
73                 .keyword = "null",
74                 .algo = RTE_CRYPTO_CIPHER_NULL,
75                 .iv_len = 0,
76                 .block_size = 4,
77                 .key_len = 0
78         },
79         {
80                 .keyword = "aes-128-cbc",
81                 .algo = RTE_CRYPTO_CIPHER_AES_CBC,
82                 .iv_len = 16,
83                 .block_size = 16,
84                 .key_len = 16
85         },
86         {
87                 .keyword = "aes-128-gcm",
88                 .algo = RTE_CRYPTO_CIPHER_AES_GCM,
89                 .iv_len = 8,
90                 .block_size = 4,
91                 .key_len = 20
92         },
93         {
94                 .keyword = "aes-128-ctr",
95                 .algo = RTE_CRYPTO_CIPHER_AES_CTR,
96                 .iv_len = 8,
97                 .block_size = 16, /* XXX AESNI MB limition, should be 4 */
98                 .key_len = 20
99         }
100 };
101
102 const struct supported_auth_algo auth_algos[] = {
103         {
104                 .keyword = "null",
105                 .algo = RTE_CRYPTO_AUTH_NULL,
106                 .digest_len = 0,
107                 .key_len = 0,
108                 .key_not_req = 1
109         },
110         {
111                 .keyword = "sha1-hmac",
112                 .algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
113                 .digest_len = 12,
114                 .key_len = 20
115         },
116         {
117                 .keyword = "sha256-hmac",
118                 .algo = RTE_CRYPTO_AUTH_SHA256_HMAC,
119                 .digest_len = 12,
120                 .key_len = 32
121         },
122         {
123                 .keyword = "aes-128-gcm",
124                 .algo = RTE_CRYPTO_AUTH_AES_GCM,
125                 .digest_len = 16,
126                 .aad_len = 8,
127                 .key_not_req = 1
128         }
129 };
130
131 struct ipsec_sa sa_out[IPSEC_SA_MAX_ENTRIES];
132 uint32_t nb_sa_out;
133
134 struct ipsec_sa sa_in[IPSEC_SA_MAX_ENTRIES];
135 uint32_t nb_sa_in;
136
137 static const struct supported_cipher_algo *
138 find_match_cipher_algo(const char *cipher_keyword)
139 {
140         size_t i;
141
142         for (i = 0; i < RTE_DIM(cipher_algos); i++) {
143                 const struct supported_cipher_algo *algo =
144                         &cipher_algos[i];
145
146                 if (strcmp(cipher_keyword, algo->keyword) == 0)
147                         return algo;
148         }
149
150         return NULL;
151 }
152
153 static const struct supported_auth_algo *
154 find_match_auth_algo(const char *auth_keyword)
155 {
156         size_t i;
157
158         for (i = 0; i < RTE_DIM(auth_algos); i++) {
159                 const struct supported_auth_algo *algo =
160                         &auth_algos[i];
161
162                 if (strcmp(auth_keyword, algo->keyword) == 0)
163                         return algo;
164         }
165
166         return NULL;
167 }
168
169 /** parse_key_string
170  *  parse x:x:x:x.... hex number key string into uint8_t *key
171  *  return:
172  *  > 0: number of bytes parsed
173  *  0:   failed
174  */
175 static uint32_t
176 parse_key_string(const char *key_str, uint8_t *key)
177 {
178         const char *pt_start = key_str, *pt_end = key_str;
179         uint32_t nb_bytes = 0;
180
181         while (pt_end != NULL) {
182                 char sub_str[3] = {0};
183
184                 pt_end = strchr(pt_start, ':');
185
186                 if (pt_end == NULL) {
187                         if (strlen(pt_start) > 2)
188                                 return 0;
189                         strncpy(sub_str, pt_start, 2);
190                 } else {
191                         if (pt_end - pt_start > 2)
192                                 return 0;
193
194                         strncpy(sub_str, pt_start, pt_end - pt_start);
195                         pt_start = pt_end + 1;
196                 }
197
198                 key[nb_bytes++] = strtol(sub_str, NULL, 16);
199         }
200
201         return nb_bytes;
202 }
203
204 void
205 parse_sa_tokens(char **tokens, uint32_t n_tokens,
206         struct parse_status *status)
207 {
208         struct ipsec_sa *rule = NULL;
209         uint32_t ti; /*token index*/
210         uint32_t *ri /*rule index*/;
211         uint32_t cipher_algo_p = 0;
212         uint32_t auth_algo_p = 0;
213         uint32_t src_p = 0;
214         uint32_t dst_p = 0;
215         uint32_t mode_p = 0;
216
217         if (strcmp(tokens[0], "in") == 0) {
218                 ri = &nb_sa_in;
219
220                 APP_CHECK(*ri <= IPSEC_SA_MAX_ENTRIES - 1, status,
221                         "too many sa rules, abort insertion\n");
222                 if (status->status < 0)
223                         return;
224
225                 rule = &sa_in[*ri];
226         } else {
227                 ri = &nb_sa_out;
228
229                 APP_CHECK(*ri <= IPSEC_SA_MAX_ENTRIES - 1, status,
230                         "too many sa rules, abort insertion\n");
231                 if (status->status < 0)
232                         return;
233
234                 rule = &sa_out[*ri];
235         }
236
237         /* spi number */
238         APP_CHECK_TOKEN_IS_NUM(tokens, 1, status);
239         if (status->status < 0)
240                 return;
241         rule->spi = atoi(tokens[1]);
242
243         for (ti = 2; ti < n_tokens; ti++) {
244                 if (strcmp(tokens[ti], "mode") == 0) {
245                         APP_CHECK_PRESENCE(mode_p, tokens[ti], status);
246                         if (status->status < 0)
247                                 return;
248
249                         INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
250                         if (status->status < 0)
251                                 return;
252
253                         if (strcmp(tokens[ti], "ipv4-tunnel") == 0)
254                                 rule->flags = IP4_TUNNEL;
255                         else if (strcmp(tokens[ti], "ipv6-tunnel") == 0)
256                                 rule->flags = IP6_TUNNEL;
257                         else if (strcmp(tokens[ti], "transport") == 0)
258                                 rule->flags = TRANSPORT;
259                         else {
260                                 APP_CHECK(0, status, "unrecognized "
261                                         "input \"%s\"", tokens[ti]);
262                                 return;
263                         }
264
265                         mode_p = 1;
266                         continue;
267                 }
268
269                 if (strcmp(tokens[ti], "cipher_algo") == 0) {
270                         const struct supported_cipher_algo *algo;
271                         uint32_t key_len;
272
273                         APP_CHECK_PRESENCE(cipher_algo_p, tokens[ti],
274                                 status);
275                         if (status->status < 0)
276                                 return;
277
278                         INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
279                         if (status->status < 0)
280                                 return;
281
282                         algo = find_match_cipher_algo(tokens[ti]);
283
284                         APP_CHECK(algo != NULL, status, "unrecognized "
285                                 "input \"%s\"", tokens[ti]);
286
287                         rule->cipher_algo = algo->algo;
288                         rule->block_size = algo->block_size;
289                         rule->iv_len = algo->iv_len;
290                         rule->cipher_key_len = algo->key_len;
291
292                         /* for NULL algorithm, no cipher key required */
293                         if (rule->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
294                                 cipher_algo_p = 1;
295                                 continue;
296                         }
297
298                         INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
299                         if (status->status < 0)
300                                 return;
301
302                         APP_CHECK(strcmp(tokens[ti], "cipher_key") == 0,
303                                 status, "unrecognized input \"%s\", "
304                                 "expect \"cipher_key\"", tokens[ti]);
305                         if (status->status < 0)
306                                 return;
307
308                         INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
309                         if (status->status < 0)
310                                 return;
311
312                         key_len = parse_key_string(tokens[ti],
313                                 rule->cipher_key);
314                         APP_CHECK(key_len == rule->cipher_key_len, status,
315                                 "unrecognized input \"%s\"", tokens[ti]);
316                         if (status->status < 0)
317                                 return;
318
319                         if (algo->algo == RTE_CRYPTO_CIPHER_AES_CBC)
320                                 rule->salt = (uint32_t)rte_rand();
321
322                         if ((algo->algo == RTE_CRYPTO_CIPHER_AES_CTR) ||
323                                 (algo->algo == RTE_CRYPTO_CIPHER_AES_GCM)) {
324                                 key_len -= 4;
325                                 rule->cipher_key_len = key_len;
326                                 memcpy(&rule->salt,
327                                         &rule->cipher_key[key_len], 4);
328                         }
329
330                         cipher_algo_p = 1;
331                         continue;
332                 }
333
334                 if (strcmp(tokens[ti], "auth_algo") == 0) {
335                         const struct supported_auth_algo *algo;
336                         uint32_t key_len;
337
338                         APP_CHECK_PRESENCE(auth_algo_p, tokens[ti],
339                                 status);
340                         if (status->status < 0)
341                                 return;
342
343                         INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
344                         if (status->status < 0)
345                                 return;
346
347                         algo = find_match_auth_algo(tokens[ti]);
348                         APP_CHECK(algo != NULL, status, "unrecognized "
349                                 "input \"%s\"", tokens[ti]);
350
351                         rule->auth_algo = algo->algo;
352                         rule->auth_key_len = algo->key_len;
353                         rule->digest_len = algo->digest_len;
354                         rule->aad_len = algo->key_len;
355
356                         /* NULL algorithm and combined algos do not
357                          * require auth key
358                          */
359                         if (algo->key_not_req) {
360                                 auth_algo_p = 1;
361                                 continue;
362                         }
363
364                         INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
365                         if (status->status < 0)
366                                 return;
367
368                         APP_CHECK(strcmp(tokens[ti], "auth_key") == 0,
369                                 status, "unrecognized input \"%s\", "
370                                 "expect \"auth_key\"", tokens[ti]);
371                         if (status->status < 0)
372                                 return;
373
374                         INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
375                         if (status->status < 0)
376                                 return;
377
378                         key_len = parse_key_string(tokens[ti],
379                                 rule->auth_key);
380                         APP_CHECK(key_len == rule->auth_key_len, status,
381                                 "unrecognized input \"%s\"", tokens[ti]);
382                         if (status->status < 0)
383                                 return;
384
385                         auth_algo_p = 1;
386                         continue;
387                 }
388
389                 if (strcmp(tokens[ti], "src") == 0) {
390                         APP_CHECK_PRESENCE(src_p, tokens[ti], status);
391                         if (status->status < 0)
392                                 return;
393
394                         INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
395                         if (status->status < 0)
396                                 return;
397
398                         if (rule->flags == IP4_TUNNEL) {
399                                 struct in_addr ip;
400
401                                 APP_CHECK(parse_ipv4_addr(tokens[ti],
402                                         &ip, NULL) == 0, status,
403                                         "unrecognized input \"%s\", "
404                                         "expect valid ipv4 addr",
405                                         tokens[ti]);
406                                 if (status->status < 0)
407                                         return;
408                                 rule->src.ip.ip4 = rte_bswap32(
409                                         (uint32_t)ip.s_addr);
410                         } else if (rule->flags == IP6_TUNNEL) {
411                                 struct in6_addr ip;
412
413                                 APP_CHECK(parse_ipv6_addr(tokens[ti], &ip,
414                                         NULL) == 0, status,
415                                         "unrecognized input \"%s\", "
416                                         "expect valid ipv6 addr",
417                                         tokens[ti]);
418                                 if (status->status < 0)
419                                         return;
420                                 memcpy(rule->src.ip.ip6.ip6_b,
421                                         ip.s6_addr, 16);
422                         } else if (rule->flags == TRANSPORT) {
423                                 APP_CHECK(0, status, "unrecognized input "
424                                         "\"%s\"", tokens[ti]);
425                                 return;
426                         }
427
428                         src_p = 1;
429                         continue;
430                 }
431
432                 if (strcmp(tokens[ti], "dst") == 0) {
433                         APP_CHECK_PRESENCE(dst_p, tokens[ti], status);
434                         if (status->status < 0)
435                                 return;
436
437                         INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
438                         if (status->status < 0)
439                                 return;
440
441                         if (rule->flags == IP4_TUNNEL) {
442                                 struct in_addr ip;
443
444                                 APP_CHECK(parse_ipv4_addr(tokens[ti],
445                                         &ip, NULL) == 0, status,
446                                         "unrecognized input \"%s\", "
447                                         "expect valid ipv4 addr",
448                                         tokens[ti]);
449                                 if (status->status < 0)
450                                         return;
451                                 rule->dst.ip.ip4 = rte_bswap32(
452                                         (uint32_t)ip.s_addr);
453                         } else if (rule->flags == IP6_TUNNEL) {
454                                 struct in6_addr ip;
455
456                                 APP_CHECK(parse_ipv6_addr(tokens[ti], &ip,
457                                         NULL) == 0, status,
458                                         "unrecognized input \"%s\", "
459                                         "expect valid ipv6 addr",
460                                         tokens[ti]);
461                                 if (status->status < 0)
462                                         return;
463                                 memcpy(rule->dst.ip.ip6.ip6_b, ip.s6_addr, 16);
464                         } else if (rule->flags == TRANSPORT) {
465                                 APP_CHECK(0, status, "unrecognized "
466                                         "input \"%s\"", tokens[ti]);
467                                 return;
468                         }
469
470                         dst_p = 1;
471                         continue;
472                 }
473
474                 /* unrecognizeable input */
475                 APP_CHECK(0, status, "unrecognized input \"%s\"",
476                         tokens[ti]);
477                 return;
478         }
479
480         APP_CHECK(cipher_algo_p == 1, status, "missing cipher options");
481         if (status->status < 0)
482                 return;
483
484         APP_CHECK(auth_algo_p == 1, status, "missing auth options");
485         if (status->status < 0)
486                 return;
487
488         APP_CHECK(mode_p == 1, status, "missing mode option");
489         if (status->status < 0)
490                 return;
491
492         *ri = *ri + 1;
493 }
494
495 static inline void
496 print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
497 {
498         uint32_t i;
499         uint8_t a, b, c, d;
500
501         printf("\tspi_%s(%3u):", inbound?"in":"out", sa->spi);
502
503         for (i = 0; i < RTE_DIM(cipher_algos); i++) {
504                 if (cipher_algos[i].algo == sa->cipher_algo) {
505                         printf("%s ", cipher_algos[i].keyword);
506                         break;
507                 }
508         }
509
510         for (i = 0; i < RTE_DIM(auth_algos); i++) {
511                 if (auth_algos[i].algo == sa->auth_algo) {
512                         printf("%s ", auth_algos[i].keyword);
513                         break;
514                 }
515         }
516
517         printf("mode:");
518
519         switch (sa->flags) {
520         case IP4_TUNNEL:
521                 printf("IP4Tunnel ");
522                 uint32_t_to_char(sa->src.ip.ip4, &a, &b, &c, &d);
523                 printf("%hhu.%hhu.%hhu.%hhu ", d, c, b, a);
524                 uint32_t_to_char(sa->dst.ip.ip4, &a, &b, &c, &d);
525                 printf("%hhu.%hhu.%hhu.%hhu", d, c, b, a);
526                 break;
527         case IP6_TUNNEL:
528                 printf("IP6Tunnel ");
529                 for (i = 0; i < 16; i++) {
530                         if (i % 2 && i != 15)
531                                 printf("%.2x:", sa->src.ip.ip6.ip6_b[i]);
532                         else
533                                 printf("%.2x", sa->src.ip.ip6.ip6_b[i]);
534                 }
535                 printf(" ");
536                 for (i = 0; i < 16; i++) {
537                         if (i % 2 && i != 15)
538                                 printf("%.2x:", sa->dst.ip.ip6.ip6_b[i]);
539                         else
540                                 printf("%.2x", sa->dst.ip.ip6.ip6_b[i]);
541                 }
542                 break;
543         case TRANSPORT:
544                 printf("Transport");
545                 break;
546         }
547         printf("\n");
548 }
549
550 struct sa_ctx {
551         struct ipsec_sa sa[IPSEC_SA_MAX_ENTRIES];
552         struct {
553                 struct rte_crypto_sym_xform a;
554                 struct rte_crypto_sym_xform b;
555         } xf[IPSEC_SA_MAX_ENTRIES];
556 };
557
558 static struct sa_ctx *
559 sa_create(const char *name, int32_t socket_id)
560 {
561         char s[PATH_MAX];
562         struct sa_ctx *sa_ctx;
563         uint32_t mz_size;
564         const struct rte_memzone *mz;
565
566         snprintf(s, sizeof(s), "%s_%u", name, socket_id);
567
568         /* Create SA array table */
569         printf("Creating SA context with %u maximum entries\n",
570                         IPSEC_SA_MAX_ENTRIES);
571
572         mz_size = sizeof(struct sa_ctx);
573         mz = rte_memzone_reserve(s, mz_size, socket_id,
574                         RTE_MEMZONE_1GB | RTE_MEMZONE_SIZE_HINT_ONLY);
575         if (mz == NULL) {
576                 printf("Failed to allocate SA DB memory\n");
577                 rte_errno = -ENOMEM;
578                 return NULL;
579         }
580
581         sa_ctx = (struct sa_ctx *)mz->addr;
582
583         return sa_ctx;
584 }
585
586 static int
587 sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
588                 uint32_t nb_entries, uint32_t inbound)
589 {
590         struct ipsec_sa *sa;
591         uint32_t i, idx;
592         uint16_t iv_length;
593
594         for (i = 0; i < nb_entries; i++) {
595                 idx = SPI2IDX(entries[i].spi);
596                 sa = &sa_ctx->sa[idx];
597                 if (sa->spi != 0) {
598                         printf("Index %u already in use by SPI %u\n",
599                                         idx, sa->spi);
600                         return -EINVAL;
601                 }
602                 *sa = entries[i];
603                 sa->seq = 0;
604
605                 switch (sa->flags) {
606                 case IP4_TUNNEL:
607                         sa->src.ip.ip4 = rte_cpu_to_be_32(sa->src.ip.ip4);
608                         sa->dst.ip.ip4 = rte_cpu_to_be_32(sa->dst.ip.ip4);
609                 }
610
611                 switch (sa->cipher_algo) {
612                 case RTE_CRYPTO_CIPHER_NULL:
613                 case RTE_CRYPTO_CIPHER_AES_CBC:
614                         iv_length = sa->iv_len;
615                         break;
616                 case RTE_CRYPTO_CIPHER_AES_CTR:
617                 case RTE_CRYPTO_CIPHER_AES_GCM:
618                         iv_length = 16;
619                         break;
620                 default:
621                         RTE_LOG(ERR, IPSEC_ESP, "unsupported cipher algorithm %u\n",
622                                         sa->cipher_algo);
623                         return -EINVAL;
624                 }
625
626                 if (inbound) {
627                         sa_ctx->xf[idx].b.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
628                         sa_ctx->xf[idx].b.cipher.algo = sa->cipher_algo;
629                         sa_ctx->xf[idx].b.cipher.key.data = sa->cipher_key;
630                         sa_ctx->xf[idx].b.cipher.key.length =
631                                 sa->cipher_key_len;
632                         sa_ctx->xf[idx].b.cipher.op =
633                                 RTE_CRYPTO_CIPHER_OP_DECRYPT;
634                         sa_ctx->xf[idx].b.cipher.iv.offset = IV_OFFSET;
635                         sa_ctx->xf[idx].b.cipher.iv.length = iv_length;
636                         sa_ctx->xf[idx].b.next = NULL;
637
638                         sa_ctx->xf[idx].a.type = RTE_CRYPTO_SYM_XFORM_AUTH;
639                         sa_ctx->xf[idx].a.auth.algo = sa->auth_algo;
640                         sa_ctx->xf[idx].a.auth.add_auth_data_length =
641                                 sa->aad_len;
642                         sa_ctx->xf[idx].a.auth.key.data = sa->auth_key;
643                         sa_ctx->xf[idx].a.auth.key.length =
644                                 sa->auth_key_len;
645                         sa_ctx->xf[idx].a.auth.digest_length =
646                                 sa->digest_len;
647                         sa_ctx->xf[idx].a.auth.op =
648                                 RTE_CRYPTO_AUTH_OP_VERIFY;
649
650                 } else { /* outbound */
651                         sa_ctx->xf[idx].a.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
652                         sa_ctx->xf[idx].a.cipher.algo = sa->cipher_algo;
653                         sa_ctx->xf[idx].a.cipher.key.data = sa->cipher_key;
654                         sa_ctx->xf[idx].a.cipher.key.length =
655                                 sa->cipher_key_len;
656                         sa_ctx->xf[idx].a.cipher.op =
657                                 RTE_CRYPTO_CIPHER_OP_ENCRYPT;
658                         sa_ctx->xf[idx].a.cipher.iv.offset = IV_OFFSET;
659                         sa_ctx->xf[idx].a.cipher.iv.length = iv_length;
660                         sa_ctx->xf[idx].a.next = NULL;
661
662                         sa_ctx->xf[idx].b.type = RTE_CRYPTO_SYM_XFORM_AUTH;
663                         sa_ctx->xf[idx].b.auth.algo = sa->auth_algo;
664                         sa_ctx->xf[idx].b.auth.add_auth_data_length =
665                                 sa->aad_len;
666                         sa_ctx->xf[idx].b.auth.key.data = sa->auth_key;
667                         sa_ctx->xf[idx].b.auth.key.length =
668                                 sa->auth_key_len;
669                         sa_ctx->xf[idx].b.auth.digest_length =
670                                 sa->digest_len;
671                         sa_ctx->xf[idx].b.auth.op =
672                                 RTE_CRYPTO_AUTH_OP_GENERATE;
673                 }
674
675                 sa_ctx->xf[idx].a.next = &sa_ctx->xf[idx].b;
676                 sa_ctx->xf[idx].b.next = NULL;
677                 sa->xforms = &sa_ctx->xf[idx].a;
678
679                 print_one_sa_rule(sa, inbound);
680         }
681
682         return 0;
683 }
684
685 static inline int
686 sa_out_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
687                 uint32_t nb_entries)
688 {
689         return sa_add_rules(sa_ctx, entries, nb_entries, 0);
690 }
691
692 static inline int
693 sa_in_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
694                 uint32_t nb_entries)
695 {
696         return sa_add_rules(sa_ctx, entries, nb_entries, 1);
697 }
698
699 void
700 sa_init(struct socket_ctx *ctx, int32_t socket_id)
701 {
702         const char *name;
703
704         if (ctx == NULL)
705                 rte_exit(EXIT_FAILURE, "NULL context.\n");
706
707         if (ctx->sa_in != NULL)
708                 rte_exit(EXIT_FAILURE, "Inbound SA DB for socket %u already "
709                                 "initialized\n", socket_id);
710
711         if (ctx->sa_out != NULL)
712                 rte_exit(EXIT_FAILURE, "Outbound SA DB for socket %u already "
713                                 "initialized\n", socket_id);
714
715         if (nb_sa_in > 0) {
716                 name = "sa_in";
717                 ctx->sa_in = sa_create(name, socket_id);
718                 if (ctx->sa_in == NULL)
719                         rte_exit(EXIT_FAILURE, "Error [%d] creating SA "
720                                 "context %s in socket %d\n", rte_errno,
721                                 name, socket_id);
722
723                 sa_in_add_rules(ctx->sa_in, sa_in, nb_sa_in);
724         } else
725                 RTE_LOG(WARNING, IPSEC, "No SA Inbound rule specified\n");
726
727         if (nb_sa_out > 0) {
728                 name = "sa_out";
729                 ctx->sa_out = sa_create(name, socket_id);
730                 if (ctx->sa_out == NULL)
731                         rte_exit(EXIT_FAILURE, "Error [%d] creating SA "
732                                 "context %s in socket %d\n", rte_errno,
733                                 name, socket_id);
734
735                 sa_out_add_rules(ctx->sa_out, sa_out, nb_sa_out);
736         } else
737                 RTE_LOG(WARNING, IPSEC, "No SA Outbound rule "
738                         "specified\n");
739 }
740
741 int
742 inbound_sa_check(struct sa_ctx *sa_ctx, struct rte_mbuf *m, uint32_t sa_idx)
743 {
744         struct ipsec_mbuf_metadata *priv;
745
746         priv = RTE_PTR_ADD(m, sizeof(struct rte_mbuf));
747
748         return (sa_ctx->sa[sa_idx].spi == priv->sa->spi);
749 }
750
751 static inline void
752 single_inbound_lookup(struct ipsec_sa *sadb, struct rte_mbuf *pkt,
753                 struct ipsec_sa **sa_ret)
754 {
755         struct esp_hdr *esp;
756         struct ip *ip;
757         uint32_t *src4_addr;
758         uint8_t *src6_addr;
759         struct ipsec_sa *sa;
760
761         *sa_ret = NULL;
762
763         ip = rte_pktmbuf_mtod(pkt, struct ip *);
764         if (ip->ip_v == IPVERSION)
765                 esp = (struct esp_hdr *)(ip + 1);
766         else
767                 esp = (struct esp_hdr *)(((struct ip6_hdr *)ip) + 1);
768
769         if (esp->spi == INVALID_SPI)
770                 return;
771
772         sa = &sadb[SPI2IDX(rte_be_to_cpu_32(esp->spi))];
773         if (rte_be_to_cpu_32(esp->spi) != sa->spi)
774                 return;
775
776         switch (sa->flags) {
777         case IP4_TUNNEL:
778                 src4_addr = RTE_PTR_ADD(ip, offsetof(struct ip, ip_src));
779                 if ((ip->ip_v == IPVERSION) &&
780                                 (sa->src.ip.ip4 == *src4_addr) &&
781                                 (sa->dst.ip.ip4 == *(src4_addr + 1)))
782                         *sa_ret = sa;
783                 break;
784         case IP6_TUNNEL:
785                 src6_addr = RTE_PTR_ADD(ip, offsetof(struct ip6_hdr, ip6_src));
786                 if ((ip->ip_v == IP6_VERSION) &&
787                                 !memcmp(&sa->src.ip.ip6.ip6, src6_addr, 16) &&
788                                 !memcmp(&sa->dst.ip.ip6.ip6, src6_addr + 16, 16))
789                         *sa_ret = sa;
790                 break;
791         case TRANSPORT:
792                 *sa_ret = sa;
793         }
794 }
795
796 void
797 inbound_sa_lookup(struct sa_ctx *sa_ctx, struct rte_mbuf *pkts[],
798                 struct ipsec_sa *sa[], uint16_t nb_pkts)
799 {
800         uint32_t i;
801
802         for (i = 0; i < nb_pkts; i++)
803                 single_inbound_lookup(sa_ctx->sa, pkts[i], &sa[i]);
804 }
805
806 void
807 outbound_sa_lookup(struct sa_ctx *sa_ctx, uint32_t sa_idx[],
808                 struct ipsec_sa *sa[], uint16_t nb_pkts)
809 {
810         uint32_t i;
811
812         for (i = 0; i < nb_pkts; i++)
813                 sa[i] = &sa_ctx->sa[sa_idx[i]];
814 }