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