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