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