xref: /dpdk/examples/ipsec-secgw/sa.c (revision 0fbd75a99fc9d2c8c7618d677d3f50fb9872b80c)
1d299106eSSergio Gonzalez Monroy /*-
2d299106eSSergio Gonzalez Monroy  *   BSD LICENSE
3d299106eSSergio Gonzalez Monroy  *
4d299106eSSergio Gonzalez Monroy  *   Copyright(c) 2016 Intel Corporation. All rights reserved.
5d299106eSSergio Gonzalez Monroy  *   All rights reserved.
6d299106eSSergio Gonzalez Monroy  *
7d299106eSSergio Gonzalez Monroy  *   Redistribution and use in source and binary forms, with or without
8d299106eSSergio Gonzalez Monroy  *   modification, are permitted provided that the following conditions
9d299106eSSergio Gonzalez Monroy  *   are met:
10d299106eSSergio Gonzalez Monroy  *
11d299106eSSergio Gonzalez Monroy  *     * Redistributions of source code must retain the above copyright
12d299106eSSergio Gonzalez Monroy  *       notice, this list of conditions and the following disclaimer.
13d299106eSSergio Gonzalez Monroy  *     * Redistributions in binary form must reproduce the above copyright
14d299106eSSergio Gonzalez Monroy  *       notice, this list of conditions and the following disclaimer in
15d299106eSSergio Gonzalez Monroy  *       the documentation and/or other materials provided with the
16d299106eSSergio Gonzalez Monroy  *       distribution.
17d299106eSSergio Gonzalez Monroy  *     * Neither the name of Intel Corporation nor the names of its
18d299106eSSergio Gonzalez Monroy  *       contributors may be used to endorse or promote products derived
19d299106eSSergio Gonzalez Monroy  *       from this software without specific prior written permission.
20d299106eSSergio Gonzalez Monroy  *
21d299106eSSergio Gonzalez Monroy  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22d299106eSSergio Gonzalez Monroy  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23d299106eSSergio Gonzalez Monroy  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24d299106eSSergio Gonzalez Monroy  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25d299106eSSergio Gonzalez Monroy  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26d299106eSSergio Gonzalez Monroy  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27d299106eSSergio Gonzalez Monroy  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28d299106eSSergio Gonzalez Monroy  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29d299106eSSergio Gonzalez Monroy  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30d299106eSSergio Gonzalez Monroy  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31d299106eSSergio Gonzalez Monroy  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32d299106eSSergio Gonzalez Monroy  */
33d299106eSSergio Gonzalez Monroy 
34d299106eSSergio Gonzalez Monroy /*
35d299106eSSergio Gonzalez Monroy  * Security Associations
36d299106eSSergio Gonzalez Monroy  */
3755d4c775SDaniel Mrzyglod #include <sys/types.h>
3855d4c775SDaniel Mrzyglod #include <netinet/in.h>
39d299106eSSergio Gonzalez Monroy #include <netinet/ip.h>
40906257e9SSergio Gonzalez Monroy #include <netinet/ip6.h>
41d299106eSSergio Gonzalez Monroy 
42d299106eSSergio Gonzalez Monroy #include <rte_memzone.h>
43d299106eSSergio Gonzalez Monroy #include <rte_crypto.h>
44d299106eSSergio Gonzalez Monroy #include <rte_cryptodev.h>
45d299106eSSergio Gonzalez Monroy #include <rte_byteorder.h>
46d299106eSSergio Gonzalez Monroy #include <rte_errno.h>
47906257e9SSergio Gonzalez Monroy #include <rte_ip.h>
4850d75caeSSergio Gonzalez Monroy #include <rte_random.h>
49d299106eSSergio Gonzalez Monroy 
50d299106eSSergio Gonzalez Monroy #include "ipsec.h"
51d299106eSSergio Gonzalez Monroy #include "esp.h"
520d547ed0SFan Zhang #include "parser.h"
53d299106eSSergio Gonzalez Monroy 
540d547ed0SFan Zhang struct supported_cipher_algo {
550d547ed0SFan Zhang 	const char *keyword;
560d547ed0SFan Zhang 	enum rte_crypto_cipher_algorithm algo;
570d547ed0SFan Zhang 	uint16_t iv_len;
580d547ed0SFan Zhang 	uint16_t block_size;
590d547ed0SFan Zhang 	uint16_t key_len;
600d547ed0SFan Zhang };
610d547ed0SFan Zhang 
620d547ed0SFan Zhang struct supported_auth_algo {
630d547ed0SFan Zhang 	const char *keyword;
640d547ed0SFan Zhang 	enum rte_crypto_auth_algorithm algo;
650d547ed0SFan Zhang 	uint16_t digest_len;
660d547ed0SFan Zhang 	uint16_t key_len;
67a9121c40SSergio Gonzalez Monroy 	uint8_t aad_len;
68a9121c40SSergio Gonzalez Monroy 	uint8_t key_not_req;
690d547ed0SFan Zhang };
700d547ed0SFan Zhang 
710d547ed0SFan Zhang const struct supported_cipher_algo cipher_algos[] = {
72c64278c0SSergio Gonzalez Monroy 	{
730d547ed0SFan Zhang 		.keyword = "null",
740d547ed0SFan Zhang 		.algo = RTE_CRYPTO_CIPHER_NULL,
75c64278c0SSergio Gonzalez Monroy 		.iv_len = 0,
76c64278c0SSergio Gonzalez Monroy 		.block_size = 4,
770d547ed0SFan Zhang 		.key_len = 0
78906257e9SSergio Gonzalez Monroy 	},
79906257e9SSergio Gonzalez Monroy 	{
800d547ed0SFan Zhang 		.keyword = "aes-128-cbc",
810d547ed0SFan Zhang 		.algo = RTE_CRYPTO_CIPHER_AES_CBC,
820d547ed0SFan Zhang 		.iv_len = 16,
830d547ed0SFan Zhang 		.block_size = 16,
840d547ed0SFan Zhang 		.key_len = 16
85a9121c40SSergio Gonzalez Monroy 	},
86a9121c40SSergio Gonzalez Monroy 	{
87a9121c40SSergio Gonzalez Monroy 		.keyword = "aes-128-gcm",
88a9121c40SSergio Gonzalez Monroy 		.algo = RTE_CRYPTO_CIPHER_AES_GCM,
89a9121c40SSergio Gonzalez Monroy 		.iv_len = 8,
90a9121c40SSergio Gonzalez Monroy 		.block_size = 4,
9150d75caeSSergio Gonzalez Monroy 		.key_len = 20
924470c22dSSergio Gonzalez Monroy 	},
934470c22dSSergio Gonzalez Monroy 	{
944470c22dSSergio Gonzalez Monroy 		.keyword = "aes-128-ctr",
954470c22dSSergio Gonzalez Monroy 		.algo = RTE_CRYPTO_CIPHER_AES_CTR,
964470c22dSSergio Gonzalez Monroy 		.iv_len = 8,
974470c22dSSergio Gonzalez Monroy 		.block_size = 16, /* XXX AESNI MB limition, should be 4 */
9850d75caeSSergio Gonzalez Monroy 		.key_len = 20
990d547ed0SFan Zhang 	}
1000d547ed0SFan Zhang };
1010d547ed0SFan Zhang 
1020d547ed0SFan Zhang const struct supported_auth_algo auth_algos[] = {
1030d547ed0SFan Zhang 	{
1040d547ed0SFan Zhang 		.keyword = "null",
1050d547ed0SFan Zhang 		.algo = RTE_CRYPTO_AUTH_NULL,
106906257e9SSergio Gonzalez Monroy 		.digest_len = 0,
107a9121c40SSergio Gonzalez Monroy 		.key_len = 0,
108a9121c40SSergio Gonzalez Monroy 		.key_not_req = 1
109906257e9SSergio Gonzalez Monroy 	},
110906257e9SSergio Gonzalez Monroy 	{
1110d547ed0SFan Zhang 		.keyword = "sha1-hmac",
1120d547ed0SFan Zhang 		.algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
113906257e9SSergio Gonzalez Monroy 		.digest_len = 12,
1140d547ed0SFan Zhang 		.key_len = 20
115a9121c40SSergio Gonzalez Monroy 	},
116a9121c40SSergio Gonzalez Monroy 	{
117b5350285SZbigniew Bodek 		.keyword = "sha256-hmac",
118b5350285SZbigniew Bodek 		.algo = RTE_CRYPTO_AUTH_SHA256_HMAC,
119b5350285SZbigniew Bodek 		.digest_len = 12,
120b5350285SZbigniew Bodek 		.key_len = 32
121b5350285SZbigniew Bodek 	},
122b5350285SZbigniew Bodek 	{
123a9121c40SSergio Gonzalez Monroy 		.keyword = "aes-128-gcm",
124a9121c40SSergio Gonzalez Monroy 		.algo = RTE_CRYPTO_AUTH_AES_GCM,
125a9121c40SSergio Gonzalez Monroy 		.digest_len = 16,
126a9121c40SSergio Gonzalez Monroy 		.aad_len = 8,
127a9121c40SSergio Gonzalez Monroy 		.key_not_req = 1
12866085224SPablo de Lara 	}
129d299106eSSergio Gonzalez Monroy };
130d299106eSSergio Gonzalez Monroy 
1310d547ed0SFan Zhang struct ipsec_sa sa_out[IPSEC_SA_MAX_ENTRIES];
1320d547ed0SFan Zhang uint32_t nb_sa_out;
133d299106eSSergio Gonzalez Monroy 
1340d547ed0SFan Zhang struct ipsec_sa sa_in[IPSEC_SA_MAX_ENTRIES];
1350d547ed0SFan Zhang uint32_t nb_sa_in;
136d299106eSSergio Gonzalez Monroy 
1370d547ed0SFan Zhang static const struct supported_cipher_algo *
1380d547ed0SFan Zhang find_match_cipher_algo(const char *cipher_keyword)
1390d547ed0SFan Zhang {
1400d547ed0SFan Zhang 	size_t i;
141d299106eSSergio Gonzalez Monroy 
1420d547ed0SFan Zhang 	for (i = 0; i < RTE_DIM(cipher_algos); i++) {
1430d547ed0SFan Zhang 		const struct supported_cipher_algo *algo =
1440d547ed0SFan Zhang 			&cipher_algos[i];
145d299106eSSergio Gonzalez Monroy 
1460d547ed0SFan Zhang 		if (strcmp(cipher_keyword, algo->keyword) == 0)
1470d547ed0SFan Zhang 			return algo;
14866085224SPablo de Lara 	}
149d299106eSSergio Gonzalez Monroy 
1500d547ed0SFan Zhang 	return NULL;
15166085224SPablo de Lara }
1520d547ed0SFan Zhang 
1530d547ed0SFan Zhang static const struct supported_auth_algo *
1540d547ed0SFan Zhang find_match_auth_algo(const char *auth_keyword)
1550d547ed0SFan Zhang {
1560d547ed0SFan Zhang 	size_t i;
1570d547ed0SFan Zhang 
1580d547ed0SFan Zhang 	for (i = 0; i < RTE_DIM(auth_algos); i++) {
1590d547ed0SFan Zhang 		const struct supported_auth_algo *algo =
1600d547ed0SFan Zhang 			&auth_algos[i];
1610d547ed0SFan Zhang 
1620d547ed0SFan Zhang 		if (strcmp(auth_keyword, algo->keyword) == 0)
1630d547ed0SFan Zhang 			return algo;
1640d547ed0SFan Zhang 	}
1650d547ed0SFan Zhang 
1660d547ed0SFan Zhang 	return NULL;
1670d547ed0SFan Zhang }
1680d547ed0SFan Zhang 
1690d547ed0SFan Zhang /** parse_key_string
1700d547ed0SFan Zhang  *  parse x:x:x:x.... hex number key string into uint8_t *key
1710d547ed0SFan Zhang  *  return:
1720d547ed0SFan Zhang  *  > 0: number of bytes parsed
1730d547ed0SFan Zhang  *  0:   failed
1740d547ed0SFan Zhang  */
1750d547ed0SFan Zhang static uint32_t
1760d547ed0SFan Zhang parse_key_string(const char *key_str, uint8_t *key)
1770d547ed0SFan Zhang {
1780d547ed0SFan Zhang 	const char *pt_start = key_str, *pt_end = key_str;
1790d547ed0SFan Zhang 	uint32_t nb_bytes = 0;
1800d547ed0SFan Zhang 
1810d547ed0SFan Zhang 	while (pt_end != NULL) {
18263e8c07cSFan Zhang 		char sub_str[3] = {0};
18363e8c07cSFan Zhang 
1840d547ed0SFan Zhang 		pt_end = strchr(pt_start, ':');
1850d547ed0SFan Zhang 
18663e8c07cSFan Zhang 		if (pt_end == NULL) {
18763e8c07cSFan Zhang 			if (strlen(pt_start) > 2)
18863e8c07cSFan Zhang 				return 0;
18963e8c07cSFan Zhang 			strncpy(sub_str, pt_start, 2);
19063e8c07cSFan Zhang 		} else {
1910d547ed0SFan Zhang 			if (pt_end - pt_start > 2)
1920d547ed0SFan Zhang 				return 0;
1930d547ed0SFan Zhang 
1940d547ed0SFan Zhang 			strncpy(sub_str, pt_start, pt_end - pt_start);
1950d547ed0SFan Zhang 			pt_start = pt_end + 1;
1960d547ed0SFan Zhang 		}
1970d547ed0SFan Zhang 
1980d547ed0SFan Zhang 		key[nb_bytes++] = strtol(sub_str, NULL, 16);
1990d547ed0SFan Zhang 	}
2000d547ed0SFan Zhang 
2010d547ed0SFan Zhang 	return nb_bytes;
2020d547ed0SFan Zhang }
2030d547ed0SFan Zhang 
2040d547ed0SFan Zhang void
2050d547ed0SFan Zhang parse_sa_tokens(char **tokens, uint32_t n_tokens,
2060d547ed0SFan Zhang 	struct parse_status *status)
2070d547ed0SFan Zhang {
2080d547ed0SFan Zhang 	struct ipsec_sa *rule = NULL;
2090d547ed0SFan Zhang 	uint32_t ti; /*token index*/
2100d547ed0SFan Zhang 	uint32_t *ri /*rule index*/;
2110d547ed0SFan Zhang 	uint32_t cipher_algo_p = 0;
2120d547ed0SFan Zhang 	uint32_t auth_algo_p = 0;
2130d547ed0SFan Zhang 	uint32_t src_p = 0;
2140d547ed0SFan Zhang 	uint32_t dst_p = 0;
2150d547ed0SFan Zhang 	uint32_t mode_p = 0;
2160d547ed0SFan Zhang 
2170d547ed0SFan Zhang 	if (strcmp(tokens[0], "in") == 0) {
2180d547ed0SFan Zhang 		ri = &nb_sa_in;
2190d547ed0SFan Zhang 
2200d547ed0SFan Zhang 		APP_CHECK(*ri <= IPSEC_SA_MAX_ENTRIES - 1, status,
2210d547ed0SFan Zhang 			"too many sa rules, abort insertion\n");
2220d547ed0SFan Zhang 		if (status->status < 0)
2230d547ed0SFan Zhang 			return;
2240d547ed0SFan Zhang 
2250d547ed0SFan Zhang 		rule = &sa_in[*ri];
2260d547ed0SFan Zhang 	} else {
2270d547ed0SFan Zhang 		ri = &nb_sa_out;
2280d547ed0SFan Zhang 
2290d547ed0SFan Zhang 		APP_CHECK(*ri <= IPSEC_SA_MAX_ENTRIES - 1, status,
2300d547ed0SFan Zhang 			"too many sa rules, abort insertion\n");
2310d547ed0SFan Zhang 		if (status->status < 0)
2320d547ed0SFan Zhang 			return;
2330d547ed0SFan Zhang 
2340d547ed0SFan Zhang 		rule = &sa_out[*ri];
2350d547ed0SFan Zhang 	}
2360d547ed0SFan Zhang 
2370d547ed0SFan Zhang 	/* spi number */
2380d547ed0SFan Zhang 	APP_CHECK_TOKEN_IS_NUM(tokens, 1, status);
2390d547ed0SFan Zhang 	if (status->status < 0)
2400d547ed0SFan Zhang 		return;
2410d547ed0SFan Zhang 	rule->spi = atoi(tokens[1]);
2420d547ed0SFan Zhang 
2430d547ed0SFan Zhang 	for (ti = 2; ti < n_tokens; ti++) {
2440d547ed0SFan Zhang 		if (strcmp(tokens[ti], "mode") == 0) {
2450d547ed0SFan Zhang 			APP_CHECK_PRESENCE(mode_p, tokens[ti], status);
2460d547ed0SFan Zhang 			if (status->status < 0)
2470d547ed0SFan Zhang 				return;
2480d547ed0SFan Zhang 
2490d547ed0SFan Zhang 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
2500d547ed0SFan Zhang 			if (status->status < 0)
2510d547ed0SFan Zhang 				return;
2520d547ed0SFan Zhang 
2530d547ed0SFan Zhang 			if (strcmp(tokens[ti], "ipv4-tunnel") == 0)
2540d547ed0SFan Zhang 				rule->flags = IP4_TUNNEL;
2550d547ed0SFan Zhang 			else if (strcmp(tokens[ti], "ipv6-tunnel") == 0)
2560d547ed0SFan Zhang 				rule->flags = IP6_TUNNEL;
2570d547ed0SFan Zhang 			else if (strcmp(tokens[ti], "transport") == 0)
2580d547ed0SFan Zhang 				rule->flags = TRANSPORT;
2590d547ed0SFan Zhang 			else {
2600d547ed0SFan Zhang 				APP_CHECK(0, status, "unrecognized "
2610d547ed0SFan Zhang 					"input \"%s\"", tokens[ti]);
2620d547ed0SFan Zhang 				return;
2630d547ed0SFan Zhang 			}
2640d547ed0SFan Zhang 
2650d547ed0SFan Zhang 			mode_p = 1;
2660d547ed0SFan Zhang 			continue;
2670d547ed0SFan Zhang 		}
2680d547ed0SFan Zhang 
2690d547ed0SFan Zhang 		if (strcmp(tokens[ti], "cipher_algo") == 0) {
2700d547ed0SFan Zhang 			const struct supported_cipher_algo *algo;
2710d547ed0SFan Zhang 			uint32_t key_len;
2720d547ed0SFan Zhang 
2730d547ed0SFan Zhang 			APP_CHECK_PRESENCE(cipher_algo_p, tokens[ti],
2740d547ed0SFan Zhang 				status);
2750d547ed0SFan Zhang 			if (status->status < 0)
2760d547ed0SFan Zhang 				return;
2770d547ed0SFan Zhang 
2780d547ed0SFan Zhang 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
2790d547ed0SFan Zhang 			if (status->status < 0)
2800d547ed0SFan Zhang 				return;
2810d547ed0SFan Zhang 
2820d547ed0SFan Zhang 			algo = find_match_cipher_algo(tokens[ti]);
2830d547ed0SFan Zhang 
2840d547ed0SFan Zhang 			APP_CHECK(algo != NULL, status, "unrecognized "
2850d547ed0SFan Zhang 				"input \"%s\"", tokens[ti]);
2860d547ed0SFan Zhang 
2870d547ed0SFan Zhang 			rule->cipher_algo = algo->algo;
2880d547ed0SFan Zhang 			rule->block_size = algo->block_size;
2890d547ed0SFan Zhang 			rule->iv_len = algo->iv_len;
2900d547ed0SFan Zhang 			rule->cipher_key_len = algo->key_len;
2910d547ed0SFan Zhang 
292a9121c40SSergio Gonzalez Monroy 			/* for NULL algorithm, no cipher key required */
2930d547ed0SFan Zhang 			if (rule->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
2940d547ed0SFan Zhang 				cipher_algo_p = 1;
2950d547ed0SFan Zhang 				continue;
2960d547ed0SFan Zhang 			}
2970d547ed0SFan Zhang 
2980d547ed0SFan Zhang 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
2990d547ed0SFan Zhang 			if (status->status < 0)
3000d547ed0SFan Zhang 				return;
3010d547ed0SFan Zhang 
3020d547ed0SFan Zhang 			APP_CHECK(strcmp(tokens[ti], "cipher_key") == 0,
3030d547ed0SFan Zhang 				status, "unrecognized input \"%s\", "
3040d547ed0SFan Zhang 				"expect \"cipher_key\"", tokens[ti]);
3050d547ed0SFan Zhang 			if (status->status < 0)
3060d547ed0SFan Zhang 				return;
3070d547ed0SFan Zhang 
3080d547ed0SFan Zhang 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
3090d547ed0SFan Zhang 			if (status->status < 0)
3100d547ed0SFan Zhang 				return;
3110d547ed0SFan Zhang 
3120d547ed0SFan Zhang 			key_len = parse_key_string(tokens[ti],
3130d547ed0SFan Zhang 				rule->cipher_key);
3140d547ed0SFan Zhang 			APP_CHECK(key_len == rule->cipher_key_len, status,
3150d547ed0SFan Zhang 				"unrecognized input \"%s\"", tokens[ti]);
3160d547ed0SFan Zhang 			if (status->status < 0)
3170d547ed0SFan Zhang 				return;
3180d547ed0SFan Zhang 
31950d75caeSSergio Gonzalez Monroy 			if (algo->algo == RTE_CRYPTO_CIPHER_AES_CBC)
32050d75caeSSergio Gonzalez Monroy 				rule->salt = (uint32_t)rte_rand();
32150d75caeSSergio Gonzalez Monroy 
32250d75caeSSergio Gonzalez Monroy 			if ((algo->algo == RTE_CRYPTO_CIPHER_AES_CTR) ||
32350d75caeSSergio Gonzalez Monroy 				(algo->algo == RTE_CRYPTO_CIPHER_AES_GCM)) {
32450d75caeSSergio Gonzalez Monroy 				key_len -= 4;
32550d75caeSSergio Gonzalez Monroy 				rule->cipher_key_len = key_len;
32650d75caeSSergio Gonzalez Monroy 				memcpy(&rule->salt,
32750d75caeSSergio Gonzalez Monroy 					&rule->cipher_key[key_len], 4);
32850d75caeSSergio Gonzalez Monroy 			}
32950d75caeSSergio Gonzalez Monroy 
3300d547ed0SFan Zhang 			cipher_algo_p = 1;
3310d547ed0SFan Zhang 			continue;
3320d547ed0SFan Zhang 		}
3330d547ed0SFan Zhang 
3340d547ed0SFan Zhang 		if (strcmp(tokens[ti], "auth_algo") == 0) {
3350d547ed0SFan Zhang 			const struct supported_auth_algo *algo;
3360d547ed0SFan Zhang 			uint32_t key_len;
3370d547ed0SFan Zhang 
3380d547ed0SFan Zhang 			APP_CHECK_PRESENCE(auth_algo_p, tokens[ti],
3390d547ed0SFan Zhang 				status);
3400d547ed0SFan Zhang 			if (status->status < 0)
3410d547ed0SFan Zhang 				return;
3420d547ed0SFan Zhang 
3430d547ed0SFan Zhang 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
3440d547ed0SFan Zhang 			if (status->status < 0)
3450d547ed0SFan Zhang 				return;
3460d547ed0SFan Zhang 
3470d547ed0SFan Zhang 			algo = find_match_auth_algo(tokens[ti]);
3480d547ed0SFan Zhang 			APP_CHECK(algo != NULL, status, "unrecognized "
3490d547ed0SFan Zhang 				"input \"%s\"", tokens[ti]);
3500d547ed0SFan Zhang 
3510d547ed0SFan Zhang 			rule->auth_algo = algo->algo;
3520d547ed0SFan Zhang 			rule->auth_key_len = algo->key_len;
3530d547ed0SFan Zhang 			rule->digest_len = algo->digest_len;
354a9121c40SSergio Gonzalez Monroy 			rule->aad_len = algo->key_len;
3550d547ed0SFan Zhang 
356a9121c40SSergio Gonzalez Monroy 			/* NULL algorithm and combined algos do not
357a9121c40SSergio Gonzalez Monroy 			 * require auth key
358a9121c40SSergio Gonzalez Monroy 			 */
359a9121c40SSergio Gonzalez Monroy 			if (algo->key_not_req) {
3600d547ed0SFan Zhang 				auth_algo_p = 1;
3610d547ed0SFan Zhang 				continue;
3620d547ed0SFan Zhang 			}
3630d547ed0SFan Zhang 
3640d547ed0SFan Zhang 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
3650d547ed0SFan Zhang 			if (status->status < 0)
3660d547ed0SFan Zhang 				return;
3670d547ed0SFan Zhang 
3680d547ed0SFan Zhang 			APP_CHECK(strcmp(tokens[ti], "auth_key") == 0,
3690d547ed0SFan Zhang 				status, "unrecognized input \"%s\", "
3700d547ed0SFan Zhang 				"expect \"auth_key\"", tokens[ti]);
3710d547ed0SFan Zhang 			if (status->status < 0)
3720d547ed0SFan Zhang 				return;
3730d547ed0SFan Zhang 
3740d547ed0SFan Zhang 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
3750d547ed0SFan Zhang 			if (status->status < 0)
3760d547ed0SFan Zhang 				return;
3770d547ed0SFan Zhang 
3780d547ed0SFan Zhang 			key_len = parse_key_string(tokens[ti],
3790d547ed0SFan Zhang 				rule->auth_key);
3800d547ed0SFan Zhang 			APP_CHECK(key_len == rule->auth_key_len, status,
3810d547ed0SFan Zhang 				"unrecognized input \"%s\"", tokens[ti]);
3820d547ed0SFan Zhang 			if (status->status < 0)
3830d547ed0SFan Zhang 				return;
3840d547ed0SFan Zhang 
3850d547ed0SFan Zhang 			auth_algo_p = 1;
3860d547ed0SFan Zhang 			continue;
3870d547ed0SFan Zhang 		}
3880d547ed0SFan Zhang 
3890d547ed0SFan Zhang 		if (strcmp(tokens[ti], "src") == 0) {
3900d547ed0SFan Zhang 			APP_CHECK_PRESENCE(src_p, tokens[ti], status);
3910d547ed0SFan Zhang 			if (status->status < 0)
3920d547ed0SFan Zhang 				return;
3930d547ed0SFan Zhang 
3940d547ed0SFan Zhang 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
3950d547ed0SFan Zhang 			if (status->status < 0)
3960d547ed0SFan Zhang 				return;
3970d547ed0SFan Zhang 
3980d547ed0SFan Zhang 			if (rule->flags == IP4_TUNNEL) {
3990d547ed0SFan Zhang 				struct in_addr ip;
4000d547ed0SFan Zhang 
4010d547ed0SFan Zhang 				APP_CHECK(parse_ipv4_addr(tokens[ti],
4020d547ed0SFan Zhang 					&ip, NULL) == 0, status,
4030d547ed0SFan Zhang 					"unrecognized input \"%s\", "
4040d547ed0SFan Zhang 					"expect valid ipv4 addr",
4050d547ed0SFan Zhang 					tokens[ti]);
4060d547ed0SFan Zhang 				if (status->status < 0)
4070d547ed0SFan Zhang 					return;
4080d547ed0SFan Zhang 				rule->src.ip.ip4 = rte_bswap32(
4090d547ed0SFan Zhang 					(uint32_t)ip.s_addr);
4100d547ed0SFan Zhang 			} else if (rule->flags == IP6_TUNNEL) {
4110d547ed0SFan Zhang 				struct in6_addr ip;
4120d547ed0SFan Zhang 
4130d547ed0SFan Zhang 				APP_CHECK(parse_ipv6_addr(tokens[ti], &ip,
4140d547ed0SFan Zhang 					NULL) == 0, status,
4150d547ed0SFan Zhang 					"unrecognized input \"%s\", "
4160d547ed0SFan Zhang 					"expect valid ipv6 addr",
4170d547ed0SFan Zhang 					tokens[ti]);
4180d547ed0SFan Zhang 				if (status->status < 0)
4190d547ed0SFan Zhang 					return;
4200d547ed0SFan Zhang 				memcpy(rule->src.ip.ip6.ip6_b,
4210d547ed0SFan Zhang 					ip.s6_addr, 16);
4220d547ed0SFan Zhang 			} else if (rule->flags == TRANSPORT) {
4230d547ed0SFan Zhang 				APP_CHECK(0, status, "unrecognized input "
4240d547ed0SFan Zhang 					"\"%s\"", tokens[ti]);
4250d547ed0SFan Zhang 				return;
4260d547ed0SFan Zhang 			}
4270d547ed0SFan Zhang 
4280d547ed0SFan Zhang 			src_p = 1;
4290d547ed0SFan Zhang 			continue;
4300d547ed0SFan Zhang 		}
4310d547ed0SFan Zhang 
4320d547ed0SFan Zhang 		if (strcmp(tokens[ti], "dst") == 0) {
4330d547ed0SFan Zhang 			APP_CHECK_PRESENCE(dst_p, tokens[ti], status);
4340d547ed0SFan Zhang 			if (status->status < 0)
4350d547ed0SFan Zhang 				return;
4360d547ed0SFan Zhang 
4370d547ed0SFan Zhang 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
4380d547ed0SFan Zhang 			if (status->status < 0)
4390d547ed0SFan Zhang 				return;
4400d547ed0SFan Zhang 
4410d547ed0SFan Zhang 			if (rule->flags == IP4_TUNNEL) {
4420d547ed0SFan Zhang 				struct in_addr ip;
4430d547ed0SFan Zhang 
4440d547ed0SFan Zhang 				APP_CHECK(parse_ipv4_addr(tokens[ti],
4450d547ed0SFan Zhang 					&ip, NULL) == 0, status,
4460d547ed0SFan Zhang 					"unrecognized input \"%s\", "
4470d547ed0SFan Zhang 					"expect valid ipv4 addr",
4480d547ed0SFan Zhang 					tokens[ti]);
4490d547ed0SFan Zhang 				if (status->status < 0)
4500d547ed0SFan Zhang 					return;
4510d547ed0SFan Zhang 				rule->dst.ip.ip4 = rte_bswap32(
4520d547ed0SFan Zhang 					(uint32_t)ip.s_addr);
4530d547ed0SFan Zhang 			} else if (rule->flags == IP6_TUNNEL) {
4540d547ed0SFan Zhang 				struct in6_addr ip;
4550d547ed0SFan Zhang 
4560d547ed0SFan Zhang 				APP_CHECK(parse_ipv6_addr(tokens[ti], &ip,
4570d547ed0SFan Zhang 					NULL) == 0, status,
4580d547ed0SFan Zhang 					"unrecognized input \"%s\", "
4590d547ed0SFan Zhang 					"expect valid ipv6 addr",
4600d547ed0SFan Zhang 					tokens[ti]);
4610d547ed0SFan Zhang 				if (status->status < 0)
4620d547ed0SFan Zhang 					return;
4630d547ed0SFan Zhang 				memcpy(rule->dst.ip.ip6.ip6_b, ip.s6_addr, 16);
4640d547ed0SFan Zhang 			} else if (rule->flags == TRANSPORT) {
4650d547ed0SFan Zhang 				APP_CHECK(0, status, "unrecognized "
4660d547ed0SFan Zhang 					"input \"%s\"",	tokens[ti]);
4670d547ed0SFan Zhang 				return;
4680d547ed0SFan Zhang 			}
4690d547ed0SFan Zhang 
4700d547ed0SFan Zhang 			dst_p = 1;
4710d547ed0SFan Zhang 			continue;
4720d547ed0SFan Zhang 		}
4730d547ed0SFan Zhang 
4740d547ed0SFan Zhang 		/* unrecognizeable input */
4750d547ed0SFan Zhang 		APP_CHECK(0, status, "unrecognized input \"%s\"",
4760d547ed0SFan Zhang 			tokens[ti]);
4770d547ed0SFan Zhang 		return;
4780d547ed0SFan Zhang 	}
4790d547ed0SFan Zhang 
4800d547ed0SFan Zhang 	APP_CHECK(cipher_algo_p == 1, status, "missing cipher options");
4810d547ed0SFan Zhang 	if (status->status < 0)
4820d547ed0SFan Zhang 		return;
4830d547ed0SFan Zhang 
4840d547ed0SFan Zhang 	APP_CHECK(auth_algo_p == 1, status, "missing auth options");
4850d547ed0SFan Zhang 	if (status->status < 0)
4860d547ed0SFan Zhang 		return;
4870d547ed0SFan Zhang 
4880d547ed0SFan Zhang 	APP_CHECK(mode_p == 1, status, "missing mode option");
4890d547ed0SFan Zhang 	if (status->status < 0)
4900d547ed0SFan Zhang 		return;
4910d547ed0SFan Zhang 
4920d547ed0SFan Zhang 	*ri = *ri + 1;
4930d547ed0SFan Zhang }
4940d547ed0SFan Zhang 
4950d547ed0SFan Zhang static inline void
4960d547ed0SFan Zhang print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
4970d547ed0SFan Zhang {
4980d547ed0SFan Zhang 	uint32_t i;
4990d547ed0SFan Zhang 	uint8_t a, b, c, d;
5000d547ed0SFan Zhang 
5010d547ed0SFan Zhang 	printf("\tspi_%s(%3u):", inbound?"in":"out", sa->spi);
5020d547ed0SFan Zhang 
5030d547ed0SFan Zhang 	for (i = 0; i < RTE_DIM(cipher_algos); i++) {
5040d547ed0SFan Zhang 		if (cipher_algos[i].algo == sa->cipher_algo) {
5050d547ed0SFan Zhang 			printf("%s ", cipher_algos[i].keyword);
5060d547ed0SFan Zhang 			break;
5070d547ed0SFan Zhang 		}
5080d547ed0SFan Zhang 	}
5090d547ed0SFan Zhang 
5100d547ed0SFan Zhang 	for (i = 0; i < RTE_DIM(auth_algos); i++) {
5110d547ed0SFan Zhang 		if (auth_algos[i].algo == sa->auth_algo) {
5120d547ed0SFan Zhang 			printf("%s ", auth_algos[i].keyword);
5130d547ed0SFan Zhang 			break;
5140d547ed0SFan Zhang 		}
5150d547ed0SFan Zhang 	}
5160d547ed0SFan Zhang 
5170d547ed0SFan Zhang 	printf("mode:");
5180d547ed0SFan Zhang 
5190d547ed0SFan Zhang 	switch (sa->flags) {
5200d547ed0SFan Zhang 	case IP4_TUNNEL:
5210d547ed0SFan Zhang 		printf("IP4Tunnel ");
5220d547ed0SFan Zhang 		uint32_t_to_char(sa->src.ip.ip4, &a, &b, &c, &d);
5230d547ed0SFan Zhang 		printf("%hhu.%hhu.%hhu.%hhu ", d, c, b, a);
5240d547ed0SFan Zhang 		uint32_t_to_char(sa->dst.ip.ip4, &a, &b, &c, &d);
5250d547ed0SFan Zhang 		printf("%hhu.%hhu.%hhu.%hhu", d, c, b, a);
5260d547ed0SFan Zhang 		break;
5270d547ed0SFan Zhang 	case IP6_TUNNEL:
5280d547ed0SFan Zhang 		printf("IP6Tunnel ");
5290d547ed0SFan Zhang 		for (i = 0; i < 16; i++) {
5300d547ed0SFan Zhang 			if (i % 2 && i != 15)
5310d547ed0SFan Zhang 				printf("%.2x:", sa->src.ip.ip6.ip6_b[i]);
5320d547ed0SFan Zhang 			else
5330d547ed0SFan Zhang 				printf("%.2x", sa->src.ip.ip6.ip6_b[i]);
5340d547ed0SFan Zhang 		}
5350d547ed0SFan Zhang 		printf(" ");
5360d547ed0SFan Zhang 		for (i = 0; i < 16; i++) {
5370d547ed0SFan Zhang 			if (i % 2 && i != 15)
5380d547ed0SFan Zhang 				printf("%.2x:", sa->dst.ip.ip6.ip6_b[i]);
5390d547ed0SFan Zhang 			else
5400d547ed0SFan Zhang 				printf("%.2x", sa->dst.ip.ip6.ip6_b[i]);
5410d547ed0SFan Zhang 		}
5420d547ed0SFan Zhang 		break;
5430d547ed0SFan Zhang 	case TRANSPORT:
5440d547ed0SFan Zhang 		printf("Transport");
5450d547ed0SFan Zhang 		break;
5460d547ed0SFan Zhang 	}
5470d547ed0SFan Zhang 	printf("\n");
5480d547ed0SFan Zhang }
549d299106eSSergio Gonzalez Monroy 
550d299106eSSergio Gonzalez Monroy struct sa_ctx {
551d299106eSSergio Gonzalez Monroy 	struct ipsec_sa sa[IPSEC_SA_MAX_ENTRIES];
552d299106eSSergio Gonzalez Monroy 	struct {
553d299106eSSergio Gonzalez Monroy 		struct rte_crypto_sym_xform a;
554d299106eSSergio Gonzalez Monroy 		struct rte_crypto_sym_xform b;
555d299106eSSergio Gonzalez Monroy 	} xf[IPSEC_SA_MAX_ENTRIES];
556d299106eSSergio Gonzalez Monroy };
557d299106eSSergio Gonzalez Monroy 
558d299106eSSergio Gonzalez Monroy static struct sa_ctx *
559906257e9SSergio Gonzalez Monroy sa_create(const char *name, int32_t socket_id)
560d299106eSSergio Gonzalez Monroy {
561d299106eSSergio Gonzalez Monroy 	char s[PATH_MAX];
562d299106eSSergio Gonzalez Monroy 	struct sa_ctx *sa_ctx;
563906257e9SSergio Gonzalez Monroy 	uint32_t mz_size;
564d299106eSSergio Gonzalez Monroy 	const struct rte_memzone *mz;
565d299106eSSergio Gonzalez Monroy 
566d299106eSSergio Gonzalez Monroy 	snprintf(s, sizeof(s), "%s_%u", name, socket_id);
567d299106eSSergio Gonzalez Monroy 
568d299106eSSergio Gonzalez Monroy 	/* Create SA array table */
569d299106eSSergio Gonzalez Monroy 	printf("Creating SA context with %u maximum entries\n",
570d299106eSSergio Gonzalez Monroy 			IPSEC_SA_MAX_ENTRIES);
571d299106eSSergio Gonzalez Monroy 
572d299106eSSergio Gonzalez Monroy 	mz_size = sizeof(struct sa_ctx);
573d299106eSSergio Gonzalez Monroy 	mz = rte_memzone_reserve(s, mz_size, socket_id,
574d299106eSSergio Gonzalez Monroy 			RTE_MEMZONE_1GB | RTE_MEMZONE_SIZE_HINT_ONLY);
575d299106eSSergio Gonzalez Monroy 	if (mz == NULL) {
576d299106eSSergio Gonzalez Monroy 		printf("Failed to allocate SA DB memory\n");
577d299106eSSergio Gonzalez Monroy 		rte_errno = -ENOMEM;
578d299106eSSergio Gonzalez Monroy 		return NULL;
579d299106eSSergio Gonzalez Monroy 	}
580d299106eSSergio Gonzalez Monroy 
581d299106eSSergio Gonzalez Monroy 	sa_ctx = (struct sa_ctx *)mz->addr;
582d299106eSSergio Gonzalez Monroy 
583d299106eSSergio Gonzalez Monroy 	return sa_ctx;
584d299106eSSergio Gonzalez Monroy }
585d299106eSSergio Gonzalez Monroy 
586d299106eSSergio Gonzalez Monroy static int
587d299106eSSergio Gonzalez Monroy sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
588906257e9SSergio Gonzalez Monroy 		uint32_t nb_entries, uint32_t inbound)
589d299106eSSergio Gonzalez Monroy {
590d299106eSSergio Gonzalez Monroy 	struct ipsec_sa *sa;
591906257e9SSergio Gonzalez Monroy 	uint32_t i, idx;
592*0fbd75a9SPablo de Lara 	uint16_t iv_length;
593d299106eSSergio Gonzalez Monroy 
594d299106eSSergio Gonzalez Monroy 	for (i = 0; i < nb_entries; i++) {
595d299106eSSergio Gonzalez Monroy 		idx = SPI2IDX(entries[i].spi);
596d299106eSSergio Gonzalez Monroy 		sa = &sa_ctx->sa[idx];
597d299106eSSergio Gonzalez Monroy 		if (sa->spi != 0) {
598d299106eSSergio Gonzalez Monroy 			printf("Index %u already in use by SPI %u\n",
599d299106eSSergio Gonzalez Monroy 					idx, sa->spi);
600d299106eSSergio Gonzalez Monroy 			return -EINVAL;
601d299106eSSergio Gonzalez Monroy 		}
602d299106eSSergio Gonzalez Monroy 		*sa = entries[i];
603906257e9SSergio Gonzalez Monroy 		sa->seq = 0;
604906257e9SSergio Gonzalez Monroy 
605906257e9SSergio Gonzalez Monroy 		switch (sa->flags) {
606906257e9SSergio Gonzalez Monroy 		case IP4_TUNNEL:
60796362fadSSergio Gonzalez Monroy 			sa->src.ip.ip4 = rte_cpu_to_be_32(sa->src.ip.ip4);
60896362fadSSergio Gonzalez Monroy 			sa->dst.ip.ip4 = rte_cpu_to_be_32(sa->dst.ip.ip4);
609906257e9SSergio Gonzalez Monroy 		}
610906257e9SSergio Gonzalez Monroy 
611*0fbd75a9SPablo de Lara 		switch (sa->cipher_algo) {
612*0fbd75a9SPablo de Lara 		case RTE_CRYPTO_CIPHER_NULL:
613*0fbd75a9SPablo de Lara 		case RTE_CRYPTO_CIPHER_AES_CBC:
614*0fbd75a9SPablo de Lara 			iv_length = sa->iv_len;
615*0fbd75a9SPablo de Lara 			break;
616*0fbd75a9SPablo de Lara 		case RTE_CRYPTO_CIPHER_AES_CTR:
617*0fbd75a9SPablo de Lara 		case RTE_CRYPTO_CIPHER_AES_GCM:
618*0fbd75a9SPablo de Lara 			iv_length = 16;
619*0fbd75a9SPablo de Lara 			break;
620*0fbd75a9SPablo de Lara 		default:
621*0fbd75a9SPablo de Lara 			RTE_LOG(ERR, IPSEC_ESP, "unsupported cipher algorithm %u\n",
622*0fbd75a9SPablo de Lara 					sa->cipher_algo);
623*0fbd75a9SPablo de Lara 			return -EINVAL;
624*0fbd75a9SPablo de Lara 		}
625*0fbd75a9SPablo de Lara 
626d299106eSSergio Gonzalez Monroy 		if (inbound) {
6270d547ed0SFan Zhang 			sa_ctx->xf[idx].b.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
6280d547ed0SFan Zhang 			sa_ctx->xf[idx].b.cipher.algo = sa->cipher_algo;
6290d547ed0SFan Zhang 			sa_ctx->xf[idx].b.cipher.key.data = sa->cipher_key;
6300d547ed0SFan Zhang 			sa_ctx->xf[idx].b.cipher.key.length =
6310d547ed0SFan Zhang 				sa->cipher_key_len;
6320d547ed0SFan Zhang 			sa_ctx->xf[idx].b.cipher.op =
6330d547ed0SFan Zhang 				RTE_CRYPTO_CIPHER_OP_DECRYPT;
634*0fbd75a9SPablo de Lara 			sa_ctx->xf[idx].b.cipher.iv.offset = IV_OFFSET;
635*0fbd75a9SPablo de Lara 			sa_ctx->xf[idx].b.cipher.iv.length = iv_length;
6360d547ed0SFan Zhang 			sa_ctx->xf[idx].b.next = NULL;
6370d547ed0SFan Zhang 
6380d547ed0SFan Zhang 			sa_ctx->xf[idx].a.type = RTE_CRYPTO_SYM_XFORM_AUTH;
6390d547ed0SFan Zhang 			sa_ctx->xf[idx].a.auth.algo = sa->auth_algo;
640a9121c40SSergio Gonzalez Monroy 			sa_ctx->xf[idx].a.auth.add_auth_data_length =
641a9121c40SSergio Gonzalez Monroy 				sa->aad_len;
6420d547ed0SFan Zhang 			sa_ctx->xf[idx].a.auth.key.data = sa->auth_key;
6430d547ed0SFan Zhang 			sa_ctx->xf[idx].a.auth.key.length =
6440d547ed0SFan Zhang 				sa->auth_key_len;
6450d547ed0SFan Zhang 			sa_ctx->xf[idx].a.auth.digest_length =
6460d547ed0SFan Zhang 				sa->digest_len;
6470d547ed0SFan Zhang 			sa_ctx->xf[idx].a.auth.op =
6480d547ed0SFan Zhang 				RTE_CRYPTO_AUTH_OP_VERIFY;
6490d547ed0SFan Zhang 
650d299106eSSergio Gonzalez Monroy 		} else { /* outbound */
6510d547ed0SFan Zhang 			sa_ctx->xf[idx].a.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
6520d547ed0SFan Zhang 			sa_ctx->xf[idx].a.cipher.algo = sa->cipher_algo;
6530d547ed0SFan Zhang 			sa_ctx->xf[idx].a.cipher.key.data = sa->cipher_key;
6540d547ed0SFan Zhang 			sa_ctx->xf[idx].a.cipher.key.length =
6550d547ed0SFan Zhang 				sa->cipher_key_len;
6560d547ed0SFan Zhang 			sa_ctx->xf[idx].a.cipher.op =
6570d547ed0SFan Zhang 				RTE_CRYPTO_CIPHER_OP_ENCRYPT;
658*0fbd75a9SPablo de Lara 			sa_ctx->xf[idx].a.cipher.iv.offset = IV_OFFSET;
659*0fbd75a9SPablo de Lara 			sa_ctx->xf[idx].a.cipher.iv.length = iv_length;
6600d547ed0SFan Zhang 			sa_ctx->xf[idx].a.next = NULL;
6610d547ed0SFan Zhang 
6620d547ed0SFan Zhang 			sa_ctx->xf[idx].b.type = RTE_CRYPTO_SYM_XFORM_AUTH;
6630d547ed0SFan Zhang 			sa_ctx->xf[idx].b.auth.algo = sa->auth_algo;
664a9121c40SSergio Gonzalez Monroy 			sa_ctx->xf[idx].b.auth.add_auth_data_length =
665a9121c40SSergio Gonzalez Monroy 				sa->aad_len;
6660d547ed0SFan Zhang 			sa_ctx->xf[idx].b.auth.key.data = sa->auth_key;
6670d547ed0SFan Zhang 			sa_ctx->xf[idx].b.auth.key.length =
6680d547ed0SFan Zhang 				sa->auth_key_len;
6690d547ed0SFan Zhang 			sa_ctx->xf[idx].b.auth.digest_length =
6700d547ed0SFan Zhang 				sa->digest_len;
6710d547ed0SFan Zhang 			sa_ctx->xf[idx].b.auth.op =
6720d547ed0SFan Zhang 				RTE_CRYPTO_AUTH_OP_GENERATE;
673d299106eSSergio Gonzalez Monroy 		}
6740d547ed0SFan Zhang 
675d299106eSSergio Gonzalez Monroy 		sa_ctx->xf[idx].a.next = &sa_ctx->xf[idx].b;
676d299106eSSergio Gonzalez Monroy 		sa_ctx->xf[idx].b.next = NULL;
677d299106eSSergio Gonzalez Monroy 		sa->xforms = &sa_ctx->xf[idx].a;
6780d547ed0SFan Zhang 
6790d547ed0SFan Zhang 		print_one_sa_rule(sa, inbound);
680d299106eSSergio Gonzalez Monroy 	}
681d299106eSSergio Gonzalez Monroy 
682d299106eSSergio Gonzalez Monroy 	return 0;
683d299106eSSergio Gonzalez Monroy }
684d299106eSSergio Gonzalez Monroy 
685d299106eSSergio Gonzalez Monroy static inline int
686d299106eSSergio Gonzalez Monroy sa_out_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
687906257e9SSergio Gonzalez Monroy 		uint32_t nb_entries)
688d299106eSSergio Gonzalez Monroy {
689d299106eSSergio Gonzalez Monroy 	return sa_add_rules(sa_ctx, entries, nb_entries, 0);
690d299106eSSergio Gonzalez Monroy }
691d299106eSSergio Gonzalez Monroy 
692d299106eSSergio Gonzalez Monroy static inline int
693d299106eSSergio Gonzalez Monroy sa_in_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
694906257e9SSergio Gonzalez Monroy 		uint32_t nb_entries)
695d299106eSSergio Gonzalez Monroy {
696d299106eSSergio Gonzalez Monroy 	return sa_add_rules(sa_ctx, entries, nb_entries, 1);
697d299106eSSergio Gonzalez Monroy }
698d299106eSSergio Gonzalez Monroy 
699d299106eSSergio Gonzalez Monroy void
7000d547ed0SFan Zhang sa_init(struct socket_ctx *ctx, int32_t socket_id)
701d299106eSSergio Gonzalez Monroy {
702d299106eSSergio Gonzalez Monroy 	const char *name;
703d299106eSSergio Gonzalez Monroy 
704d299106eSSergio Gonzalez Monroy 	if (ctx == NULL)
705d299106eSSergio Gonzalez Monroy 		rte_exit(EXIT_FAILURE, "NULL context.\n");
706d299106eSSergio Gonzalez Monroy 
707906257e9SSergio Gonzalez Monroy 	if (ctx->sa_in != NULL)
708d299106eSSergio Gonzalez Monroy 		rte_exit(EXIT_FAILURE, "Inbound SA DB for socket %u already "
709d299106eSSergio Gonzalez Monroy 				"initialized\n", socket_id);
710d299106eSSergio Gonzalez Monroy 
711906257e9SSergio Gonzalez Monroy 	if (ctx->sa_out != NULL)
712d299106eSSergio Gonzalez Monroy 		rte_exit(EXIT_FAILURE, "Outbound SA DB for socket %u already "
713d299106eSSergio Gonzalez Monroy 				"initialized\n", socket_id);
714d299106eSSergio Gonzalez Monroy 
7150d547ed0SFan Zhang 	if (nb_sa_in > 0) {
716906257e9SSergio Gonzalez Monroy 		name = "sa_in";
717906257e9SSergio Gonzalez Monroy 		ctx->sa_in = sa_create(name, socket_id);
718906257e9SSergio Gonzalez Monroy 		if (ctx->sa_in == NULL)
7190d547ed0SFan Zhang 			rte_exit(EXIT_FAILURE, "Error [%d] creating SA "
7200d547ed0SFan Zhang 				"context %s in socket %d\n", rte_errno,
7210d547ed0SFan Zhang 				name, socket_id);
722d299106eSSergio Gonzalez Monroy 
7230d547ed0SFan Zhang 		sa_in_add_rules(ctx->sa_in, sa_in, nb_sa_in);
7240d547ed0SFan Zhang 	} else
7250d547ed0SFan Zhang 		RTE_LOG(WARNING, IPSEC, "No SA Inbound rule specified\n");
7260d547ed0SFan Zhang 
7270d547ed0SFan Zhang 	if (nb_sa_out > 0) {
728906257e9SSergio Gonzalez Monroy 		name = "sa_out";
729906257e9SSergio Gonzalez Monroy 		ctx->sa_out = sa_create(name, socket_id);
730906257e9SSergio Gonzalez Monroy 		if (ctx->sa_out == NULL)
7310d547ed0SFan Zhang 			rte_exit(EXIT_FAILURE, "Error [%d] creating SA "
7320d547ed0SFan Zhang 				"context %s in socket %d\n", rte_errno,
7330d547ed0SFan Zhang 				name, socket_id);
734d299106eSSergio Gonzalez Monroy 
7350d547ed0SFan Zhang 		sa_out_add_rules(ctx->sa_out, sa_out, nb_sa_out);
7360d547ed0SFan Zhang 	} else
7370d547ed0SFan Zhang 		RTE_LOG(WARNING, IPSEC, "No SA Outbound rule "
7380d547ed0SFan Zhang 			"specified\n");
739d299106eSSergio Gonzalez Monroy }
740d299106eSSergio Gonzalez Monroy 
741d299106eSSergio Gonzalez Monroy int
742d299106eSSergio Gonzalez Monroy inbound_sa_check(struct sa_ctx *sa_ctx, struct rte_mbuf *m, uint32_t sa_idx)
743d299106eSSergio Gonzalez Monroy {
744d299106eSSergio Gonzalez Monroy 	struct ipsec_mbuf_metadata *priv;
745d299106eSSergio Gonzalez Monroy 
746d299106eSSergio Gonzalez Monroy 	priv = RTE_PTR_ADD(m, sizeof(struct rte_mbuf));
747d299106eSSergio Gonzalez Monroy 
748d299106eSSergio Gonzalez Monroy 	return (sa_ctx->sa[sa_idx].spi == priv->sa->spi);
749d299106eSSergio Gonzalez Monroy }
750d299106eSSergio Gonzalez Monroy 
751906257e9SSergio Gonzalez Monroy static inline void
752906257e9SSergio Gonzalez Monroy single_inbound_lookup(struct ipsec_sa *sadb, struct rte_mbuf *pkt,
753906257e9SSergio Gonzalez Monroy 		struct ipsec_sa **sa_ret)
754906257e9SSergio Gonzalez Monroy {
755906257e9SSergio Gonzalez Monroy 	struct esp_hdr *esp;
756906257e9SSergio Gonzalez Monroy 	struct ip *ip;
757906257e9SSergio Gonzalez Monroy 	uint32_t *src4_addr;
758906257e9SSergio Gonzalez Monroy 	uint8_t *src6_addr;
759906257e9SSergio Gonzalez Monroy 	struct ipsec_sa *sa;
760906257e9SSergio Gonzalez Monroy 
761906257e9SSergio Gonzalez Monroy 	*sa_ret = NULL;
762906257e9SSergio Gonzalez Monroy 
763906257e9SSergio Gonzalez Monroy 	ip = rte_pktmbuf_mtod(pkt, struct ip *);
764906257e9SSergio Gonzalez Monroy 	if (ip->ip_v == IPVERSION)
765906257e9SSergio Gonzalez Monroy 		esp = (struct esp_hdr *)(ip + 1);
766906257e9SSergio Gonzalez Monroy 	else
767906257e9SSergio Gonzalez Monroy 		esp = (struct esp_hdr *)(((struct ip6_hdr *)ip) + 1);
768906257e9SSergio Gonzalez Monroy 
769906257e9SSergio Gonzalez Monroy 	if (esp->spi == INVALID_SPI)
770906257e9SSergio Gonzalez Monroy 		return;
771906257e9SSergio Gonzalez Monroy 
772906257e9SSergio Gonzalez Monroy 	sa = &sadb[SPI2IDX(rte_be_to_cpu_32(esp->spi))];
773906257e9SSergio Gonzalez Monroy 	if (rte_be_to_cpu_32(esp->spi) != sa->spi)
774906257e9SSergio Gonzalez Monroy 		return;
775906257e9SSergio Gonzalez Monroy 
776906257e9SSergio Gonzalez Monroy 	switch (sa->flags) {
777906257e9SSergio Gonzalez Monroy 	case IP4_TUNNEL:
778906257e9SSergio Gonzalez Monroy 		src4_addr = RTE_PTR_ADD(ip, offsetof(struct ip, ip_src));
779906257e9SSergio Gonzalez Monroy 		if ((ip->ip_v == IPVERSION) &&
78096362fadSSergio Gonzalez Monroy 				(sa->src.ip.ip4 == *src4_addr) &&
78196362fadSSergio Gonzalez Monroy 				(sa->dst.ip.ip4 == *(src4_addr + 1)))
782906257e9SSergio Gonzalez Monroy 			*sa_ret = sa;
783906257e9SSergio Gonzalez Monroy 		break;
784906257e9SSergio Gonzalez Monroy 	case IP6_TUNNEL:
785906257e9SSergio Gonzalez Monroy 		src6_addr = RTE_PTR_ADD(ip, offsetof(struct ip6_hdr, ip6_src));
786906257e9SSergio Gonzalez Monroy 		if ((ip->ip_v == IP6_VERSION) &&
78796362fadSSergio Gonzalez Monroy 				!memcmp(&sa->src.ip.ip6.ip6, src6_addr, 16) &&
78896362fadSSergio Gonzalez Monroy 				!memcmp(&sa->dst.ip.ip6.ip6, src6_addr + 16, 16))
789906257e9SSergio Gonzalez Monroy 			*sa_ret = sa;
790f159e70bSSergio Gonzalez Monroy 		break;
791f159e70bSSergio Gonzalez Monroy 	case TRANSPORT:
792f159e70bSSergio Gonzalez Monroy 		*sa_ret = sa;
793906257e9SSergio Gonzalez Monroy 	}
794906257e9SSergio Gonzalez Monroy }
795906257e9SSergio Gonzalez Monroy 
796d299106eSSergio Gonzalez Monroy void
797d299106eSSergio Gonzalez Monroy inbound_sa_lookup(struct sa_ctx *sa_ctx, struct rte_mbuf *pkts[],
798d299106eSSergio Gonzalez Monroy 		struct ipsec_sa *sa[], uint16_t nb_pkts)
799d299106eSSergio Gonzalez Monroy {
800906257e9SSergio Gonzalez Monroy 	uint32_t i;
801d299106eSSergio Gonzalez Monroy 
802906257e9SSergio Gonzalez Monroy 	for (i = 0; i < nb_pkts; i++)
803906257e9SSergio Gonzalez Monroy 		single_inbound_lookup(sa_ctx->sa, pkts[i], &sa[i]);
804d299106eSSergio Gonzalez Monroy }
805d299106eSSergio Gonzalez Monroy 
806d299106eSSergio Gonzalez Monroy void
807d299106eSSergio Gonzalez Monroy outbound_sa_lookup(struct sa_ctx *sa_ctx, uint32_t sa_idx[],
808d299106eSSergio Gonzalez Monroy 		struct ipsec_sa *sa[], uint16_t nb_pkts)
809d299106eSSergio Gonzalez Monroy {
810906257e9SSergio Gonzalez Monroy 	uint32_t i;
811d299106eSSergio Gonzalez Monroy 
812d299106eSSergio Gonzalez Monroy 	for (i = 0; i < nb_pkts; i++)
813d299106eSSergio Gonzalez Monroy 		sa[i] = &sa_ctx->sa[sa_idx[i]];
814d299106eSSergio Gonzalez Monroy }
815