xref: /f-stack/dpdk/examples/ipsec-secgw/sa.c (revision 2d9fd380)
1d30ea906Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
2*2d9fd380Sjfb8856606  * Copyright(c) 2016-2020 Intel Corporation
3a9643ea8Slogwang  */
4a9643ea8Slogwang 
5a9643ea8Slogwang /*
6a9643ea8Slogwang  * Security Associations
7a9643ea8Slogwang  */
8a9643ea8Slogwang #include <sys/types.h>
9a9643ea8Slogwang #include <netinet/in.h>
10a9643ea8Slogwang #include <netinet/ip.h>
11a9643ea8Slogwang #include <netinet/ip6.h>
12a9643ea8Slogwang 
13a9643ea8Slogwang #include <rte_memzone.h>
14a9643ea8Slogwang #include <rte_crypto.h>
152bfe3f2eSlogwang #include <rte_security.h>
16a9643ea8Slogwang #include <rte_cryptodev.h>
17a9643ea8Slogwang #include <rte_byteorder.h>
18a9643ea8Slogwang #include <rte_errno.h>
19a9643ea8Slogwang #include <rte_ip.h>
202bfe3f2eSlogwang #include <rte_random.h>
212bfe3f2eSlogwang #include <rte_ethdev.h>
224418919fSjohnjiang #include <rte_malloc.h>
23a9643ea8Slogwang 
24a9643ea8Slogwang #include "ipsec.h"
25a9643ea8Slogwang #include "esp.h"
262bfe3f2eSlogwang #include "parser.h"
27*2d9fd380Sjfb8856606 #include "sad.h"
28a9643ea8Slogwang 
292bfe3f2eSlogwang #define IPDEFTTL 64
302bfe3f2eSlogwang 
314b05018fSfengbojiang #define IP4_FULL_MASK (sizeof(((struct ip_addr *)NULL)->ip.ip4) * CHAR_BIT)
324b05018fSfengbojiang 
334b05018fSfengbojiang #define IP6_FULL_MASK (sizeof(((struct ip_addr *)NULL)->ip.ip6.ip6) * CHAR_BIT)
344b05018fSfengbojiang 
354418919fSjohnjiang #define MBUF_NO_SEC_OFFLOAD(m) ((m->ol_flags & PKT_RX_SEC_OFFLOAD) == 0)
364418919fSjohnjiang 
372bfe3f2eSlogwang struct supported_cipher_algo {
382bfe3f2eSlogwang 	const char *keyword;
392bfe3f2eSlogwang 	enum rte_crypto_cipher_algorithm algo;
402bfe3f2eSlogwang 	uint16_t iv_len;
412bfe3f2eSlogwang 	uint16_t block_size;
422bfe3f2eSlogwang 	uint16_t key_len;
432bfe3f2eSlogwang };
442bfe3f2eSlogwang 
452bfe3f2eSlogwang struct supported_auth_algo {
462bfe3f2eSlogwang 	const char *keyword;
472bfe3f2eSlogwang 	enum rte_crypto_auth_algorithm algo;
482bfe3f2eSlogwang 	uint16_t digest_len;
492bfe3f2eSlogwang 	uint16_t key_len;
502bfe3f2eSlogwang 	uint8_t key_not_req;
512bfe3f2eSlogwang };
522bfe3f2eSlogwang 
532bfe3f2eSlogwang struct supported_aead_algo {
542bfe3f2eSlogwang 	const char *keyword;
552bfe3f2eSlogwang 	enum rte_crypto_aead_algorithm algo;
562bfe3f2eSlogwang 	uint16_t iv_len;
572bfe3f2eSlogwang 	uint16_t block_size;
582bfe3f2eSlogwang 	uint16_t digest_len;
592bfe3f2eSlogwang 	uint16_t key_len;
602bfe3f2eSlogwang 	uint8_t aad_len;
612bfe3f2eSlogwang };
622bfe3f2eSlogwang 
632bfe3f2eSlogwang 
642bfe3f2eSlogwang const struct supported_cipher_algo cipher_algos[] = {
65a9643ea8Slogwang 	{
662bfe3f2eSlogwang 		.keyword = "null",
672bfe3f2eSlogwang 		.algo = RTE_CRYPTO_CIPHER_NULL,
68a9643ea8Slogwang 		.iv_len = 0,
69a9643ea8Slogwang 		.block_size = 4,
702bfe3f2eSlogwang 		.key_len = 0
71a9643ea8Slogwang 	},
72a9643ea8Slogwang 	{
732bfe3f2eSlogwang 		.keyword = "aes-128-cbc",
742bfe3f2eSlogwang 		.algo = RTE_CRYPTO_CIPHER_AES_CBC,
752bfe3f2eSlogwang 		.iv_len = 16,
762bfe3f2eSlogwang 		.block_size = 16,
772bfe3f2eSlogwang 		.key_len = 16
782bfe3f2eSlogwang 	},
792bfe3f2eSlogwang 	{
80*2d9fd380Sjfb8856606 		.keyword = "aes-192-cbc",
81*2d9fd380Sjfb8856606 		.algo = RTE_CRYPTO_CIPHER_AES_CBC,
82*2d9fd380Sjfb8856606 		.iv_len = 16,
83*2d9fd380Sjfb8856606 		.block_size = 16,
84*2d9fd380Sjfb8856606 		.key_len = 24
85*2d9fd380Sjfb8856606 	},
86*2d9fd380Sjfb8856606 	{
87d30ea906Sjfb8856606 		.keyword = "aes-256-cbc",
88d30ea906Sjfb8856606 		.algo = RTE_CRYPTO_CIPHER_AES_CBC,
89d30ea906Sjfb8856606 		.iv_len = 16,
90d30ea906Sjfb8856606 		.block_size = 16,
91d30ea906Sjfb8856606 		.key_len = 32
92d30ea906Sjfb8856606 	},
93d30ea906Sjfb8856606 	{
942bfe3f2eSlogwang 		.keyword = "aes-128-ctr",
952bfe3f2eSlogwang 		.algo = RTE_CRYPTO_CIPHER_AES_CTR,
962bfe3f2eSlogwang 		.iv_len = 8,
971646932aSjfb8856606 		.block_size = 4,
982bfe3f2eSlogwang 		.key_len = 20
99d30ea906Sjfb8856606 	},
100d30ea906Sjfb8856606 	{
101d30ea906Sjfb8856606 		.keyword = "3des-cbc",
102d30ea906Sjfb8856606 		.algo = RTE_CRYPTO_CIPHER_3DES_CBC,
103d30ea906Sjfb8856606 		.iv_len = 8,
104d30ea906Sjfb8856606 		.block_size = 8,
105d30ea906Sjfb8856606 		.key_len = 24
1062bfe3f2eSlogwang 	}
1072bfe3f2eSlogwang };
1082bfe3f2eSlogwang 
1092bfe3f2eSlogwang const struct supported_auth_algo auth_algos[] = {
1102bfe3f2eSlogwang 	{
1112bfe3f2eSlogwang 		.keyword = "null",
1122bfe3f2eSlogwang 		.algo = RTE_CRYPTO_AUTH_NULL,
113a9643ea8Slogwang 		.digest_len = 0,
1142bfe3f2eSlogwang 		.key_len = 0,
1152bfe3f2eSlogwang 		.key_not_req = 1
1162bfe3f2eSlogwang 	},
1172bfe3f2eSlogwang 	{
1182bfe3f2eSlogwang 		.keyword = "sha1-hmac",
1192bfe3f2eSlogwang 		.algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
1202bfe3f2eSlogwang 		.digest_len = 12,
1212bfe3f2eSlogwang 		.key_len = 20
1222bfe3f2eSlogwang 	},
1232bfe3f2eSlogwang 	{
1242bfe3f2eSlogwang 		.keyword = "sha256-hmac",
1252bfe3f2eSlogwang 		.algo = RTE_CRYPTO_AUTH_SHA256_HMAC,
1264418919fSjohnjiang 		.digest_len = 16,
1272bfe3f2eSlogwang 		.key_len = 32
1282bfe3f2eSlogwang 	}
1292bfe3f2eSlogwang };
1302bfe3f2eSlogwang 
1312bfe3f2eSlogwang const struct supported_aead_algo aead_algos[] = {
1322bfe3f2eSlogwang 	{
1332bfe3f2eSlogwang 		.keyword = "aes-128-gcm",
1342bfe3f2eSlogwang 		.algo = RTE_CRYPTO_AEAD_AES_GCM,
1352bfe3f2eSlogwang 		.iv_len = 8,
136a9643ea8Slogwang 		.block_size = 4,
1372bfe3f2eSlogwang 		.key_len = 20,
1382bfe3f2eSlogwang 		.digest_len = 16,
1392bfe3f2eSlogwang 		.aad_len = 8,
140*2d9fd380Sjfb8856606 	},
141*2d9fd380Sjfb8856606 	{
142*2d9fd380Sjfb8856606 		.keyword = "aes-192-gcm",
143*2d9fd380Sjfb8856606 		.algo = RTE_CRYPTO_AEAD_AES_GCM,
144*2d9fd380Sjfb8856606 		.iv_len = 8,
145*2d9fd380Sjfb8856606 		.block_size = 4,
146*2d9fd380Sjfb8856606 		.key_len = 28,
147*2d9fd380Sjfb8856606 		.digest_len = 16,
148*2d9fd380Sjfb8856606 		.aad_len = 8,
149*2d9fd380Sjfb8856606 	},
150*2d9fd380Sjfb8856606 	{
151*2d9fd380Sjfb8856606 		.keyword = "aes-256-gcm",
152*2d9fd380Sjfb8856606 		.algo = RTE_CRYPTO_AEAD_AES_GCM,
153*2d9fd380Sjfb8856606 		.iv_len = 8,
154*2d9fd380Sjfb8856606 		.block_size = 4,
155*2d9fd380Sjfb8856606 		.key_len = 36,
156*2d9fd380Sjfb8856606 		.digest_len = 16,
157*2d9fd380Sjfb8856606 		.aad_len = 8,
158a9643ea8Slogwang 	}
159a9643ea8Slogwang };
160a9643ea8Slogwang 
161*2d9fd380Sjfb8856606 #define SA_INIT_NB	128
162a9643ea8Slogwang 
163*2d9fd380Sjfb8856606 static uint32_t nb_crypto_sessions;
164*2d9fd380Sjfb8856606 struct ipsec_sa *sa_out;
165*2d9fd380Sjfb8856606 uint32_t nb_sa_out;
166*2d9fd380Sjfb8856606 static uint32_t sa_out_sz;
167*2d9fd380Sjfb8856606 static struct ipsec_sa_cnt sa_out_cnt;
168*2d9fd380Sjfb8856606 
169*2d9fd380Sjfb8856606 struct ipsec_sa *sa_in;
170*2d9fd380Sjfb8856606 uint32_t nb_sa_in;
171*2d9fd380Sjfb8856606 static uint32_t sa_in_sz;
172*2d9fd380Sjfb8856606 static struct ipsec_sa_cnt sa_in_cnt;
173a9643ea8Slogwang 
1742bfe3f2eSlogwang static const struct supported_cipher_algo *
find_match_cipher_algo(const char * cipher_keyword)1752bfe3f2eSlogwang find_match_cipher_algo(const char *cipher_keyword)
1762bfe3f2eSlogwang {
1772bfe3f2eSlogwang 	size_t i;
178a9643ea8Slogwang 
1792bfe3f2eSlogwang 	for (i = 0; i < RTE_DIM(cipher_algos); i++) {
1802bfe3f2eSlogwang 		const struct supported_cipher_algo *algo =
1812bfe3f2eSlogwang 			&cipher_algos[i];
182a9643ea8Slogwang 
1832bfe3f2eSlogwang 		if (strcmp(cipher_keyword, algo->keyword) == 0)
1842bfe3f2eSlogwang 			return algo;
185a9643ea8Slogwang 	}
186a9643ea8Slogwang 
1872bfe3f2eSlogwang 	return NULL;
188a9643ea8Slogwang }
1892bfe3f2eSlogwang 
1902bfe3f2eSlogwang static const struct supported_auth_algo *
find_match_auth_algo(const char * auth_keyword)1912bfe3f2eSlogwang find_match_auth_algo(const char *auth_keyword)
1922bfe3f2eSlogwang {
1932bfe3f2eSlogwang 	size_t i;
1942bfe3f2eSlogwang 
1952bfe3f2eSlogwang 	for (i = 0; i < RTE_DIM(auth_algos); i++) {
1962bfe3f2eSlogwang 		const struct supported_auth_algo *algo =
1972bfe3f2eSlogwang 			&auth_algos[i];
1982bfe3f2eSlogwang 
1992bfe3f2eSlogwang 		if (strcmp(auth_keyword, algo->keyword) == 0)
2002bfe3f2eSlogwang 			return algo;
2012bfe3f2eSlogwang 	}
2022bfe3f2eSlogwang 
2032bfe3f2eSlogwang 	return NULL;
2042bfe3f2eSlogwang }
2052bfe3f2eSlogwang 
2062bfe3f2eSlogwang static const struct supported_aead_algo *
find_match_aead_algo(const char * aead_keyword)2072bfe3f2eSlogwang find_match_aead_algo(const char *aead_keyword)
2082bfe3f2eSlogwang {
2092bfe3f2eSlogwang 	size_t i;
2102bfe3f2eSlogwang 
2112bfe3f2eSlogwang 	for (i = 0; i < RTE_DIM(aead_algos); i++) {
2122bfe3f2eSlogwang 		const struct supported_aead_algo *algo =
2132bfe3f2eSlogwang 			&aead_algos[i];
2142bfe3f2eSlogwang 
2152bfe3f2eSlogwang 		if (strcmp(aead_keyword, algo->keyword) == 0)
2162bfe3f2eSlogwang 			return algo;
2172bfe3f2eSlogwang 	}
2182bfe3f2eSlogwang 
2192bfe3f2eSlogwang 	return NULL;
2202bfe3f2eSlogwang }
2212bfe3f2eSlogwang 
2222bfe3f2eSlogwang /** parse_key_string
2232bfe3f2eSlogwang  *  parse x:x:x:x.... hex number key string into uint8_t *key
2242bfe3f2eSlogwang  *  return:
2252bfe3f2eSlogwang  *  > 0: number of bytes parsed
2262bfe3f2eSlogwang  *  0:   failed
2272bfe3f2eSlogwang  */
2282bfe3f2eSlogwang static uint32_t
parse_key_string(const char * key_str,uint8_t * key)2292bfe3f2eSlogwang parse_key_string(const char *key_str, uint8_t *key)
2302bfe3f2eSlogwang {
2312bfe3f2eSlogwang 	const char *pt_start = key_str, *pt_end = key_str;
2322bfe3f2eSlogwang 	uint32_t nb_bytes = 0;
2332bfe3f2eSlogwang 
2342bfe3f2eSlogwang 	while (pt_end != NULL) {
2352bfe3f2eSlogwang 		char sub_str[3] = {0};
2362bfe3f2eSlogwang 
2372bfe3f2eSlogwang 		pt_end = strchr(pt_start, ':');
2382bfe3f2eSlogwang 
2392bfe3f2eSlogwang 		if (pt_end == NULL) {
2402bfe3f2eSlogwang 			if (strlen(pt_start) > 2)
2412bfe3f2eSlogwang 				return 0;
2422bfe3f2eSlogwang 			strncpy(sub_str, pt_start, 2);
2432bfe3f2eSlogwang 		} else {
2442bfe3f2eSlogwang 			if (pt_end - pt_start > 2)
2452bfe3f2eSlogwang 				return 0;
2462bfe3f2eSlogwang 
2472bfe3f2eSlogwang 			strncpy(sub_str, pt_start, pt_end - pt_start);
2482bfe3f2eSlogwang 			pt_start = pt_end + 1;
2492bfe3f2eSlogwang 		}
2502bfe3f2eSlogwang 
2512bfe3f2eSlogwang 		key[nb_bytes++] = strtol(sub_str, NULL, 16);
2522bfe3f2eSlogwang 	}
2532bfe3f2eSlogwang 
2542bfe3f2eSlogwang 	return nb_bytes;
2552bfe3f2eSlogwang }
2562bfe3f2eSlogwang 
257*2d9fd380Sjfb8856606 static int
extend_sa_arr(struct ipsec_sa ** sa_tbl,uint32_t cur_cnt,uint32_t * cur_sz)258*2d9fd380Sjfb8856606 extend_sa_arr(struct ipsec_sa **sa_tbl, uint32_t cur_cnt, uint32_t *cur_sz)
259*2d9fd380Sjfb8856606 {
260*2d9fd380Sjfb8856606 	if (*sa_tbl == NULL) {
261*2d9fd380Sjfb8856606 		*sa_tbl = calloc(SA_INIT_NB, sizeof(struct ipsec_sa));
262*2d9fd380Sjfb8856606 		if (*sa_tbl == NULL)
263*2d9fd380Sjfb8856606 			return -1;
264*2d9fd380Sjfb8856606 		*cur_sz = SA_INIT_NB;
265*2d9fd380Sjfb8856606 		return 0;
266*2d9fd380Sjfb8856606 	}
267*2d9fd380Sjfb8856606 
268*2d9fd380Sjfb8856606 	if (cur_cnt >= *cur_sz) {
269*2d9fd380Sjfb8856606 		*sa_tbl = realloc(*sa_tbl,
270*2d9fd380Sjfb8856606 			*cur_sz * sizeof(struct ipsec_sa) * 2);
271*2d9fd380Sjfb8856606 		if (*sa_tbl == NULL)
272*2d9fd380Sjfb8856606 			return -1;
273*2d9fd380Sjfb8856606 		/* clean reallocated extra space */
274*2d9fd380Sjfb8856606 		memset(&(*sa_tbl)[*cur_sz], 0,
275*2d9fd380Sjfb8856606 			*cur_sz * sizeof(struct ipsec_sa));
276*2d9fd380Sjfb8856606 		*cur_sz *= 2;
277*2d9fd380Sjfb8856606 	}
278*2d9fd380Sjfb8856606 
279*2d9fd380Sjfb8856606 	return 0;
280*2d9fd380Sjfb8856606 }
281*2d9fd380Sjfb8856606 
2822bfe3f2eSlogwang void
parse_sa_tokens(char ** tokens,uint32_t n_tokens,struct parse_status * status)2832bfe3f2eSlogwang parse_sa_tokens(char **tokens, uint32_t n_tokens,
2842bfe3f2eSlogwang 	struct parse_status *status)
2852bfe3f2eSlogwang {
2862bfe3f2eSlogwang 	struct ipsec_sa *rule = NULL;
2874418919fSjohnjiang 	struct rte_ipsec_session *ips;
2882bfe3f2eSlogwang 	uint32_t ti; /*token index*/
2892bfe3f2eSlogwang 	uint32_t *ri /*rule index*/;
290*2d9fd380Sjfb8856606 	struct ipsec_sa_cnt *sa_cnt;
2912bfe3f2eSlogwang 	uint32_t cipher_algo_p = 0;
2922bfe3f2eSlogwang 	uint32_t auth_algo_p = 0;
2932bfe3f2eSlogwang 	uint32_t aead_algo_p = 0;
2942bfe3f2eSlogwang 	uint32_t src_p = 0;
2952bfe3f2eSlogwang 	uint32_t dst_p = 0;
2962bfe3f2eSlogwang 	uint32_t mode_p = 0;
2972bfe3f2eSlogwang 	uint32_t type_p = 0;
2982bfe3f2eSlogwang 	uint32_t portid_p = 0;
2994418919fSjohnjiang 	uint32_t fallback_p = 0;
300*2d9fd380Sjfb8856606 	int16_t status_p = 0;
3012bfe3f2eSlogwang 
3022bfe3f2eSlogwang 	if (strcmp(tokens[0], "in") == 0) {
3032bfe3f2eSlogwang 		ri = &nb_sa_in;
304*2d9fd380Sjfb8856606 		sa_cnt = &sa_in_cnt;
305*2d9fd380Sjfb8856606 		if (extend_sa_arr(&sa_in, nb_sa_in, &sa_in_sz) < 0)
3062bfe3f2eSlogwang 			return;
3072bfe3f2eSlogwang 		rule = &sa_in[*ri];
3084418919fSjohnjiang 		rule->direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS;
3092bfe3f2eSlogwang 	} else {
3102bfe3f2eSlogwang 		ri = &nb_sa_out;
311*2d9fd380Sjfb8856606 		sa_cnt = &sa_out_cnt;
312*2d9fd380Sjfb8856606 		if (extend_sa_arr(&sa_out, nb_sa_out, &sa_out_sz) < 0)
3132bfe3f2eSlogwang 			return;
3142bfe3f2eSlogwang 		rule = &sa_out[*ri];
3154418919fSjohnjiang 		rule->direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS;
3162bfe3f2eSlogwang 	}
3172bfe3f2eSlogwang 
3182bfe3f2eSlogwang 	/* spi number */
3192bfe3f2eSlogwang 	APP_CHECK_TOKEN_IS_NUM(tokens, 1, status);
3202bfe3f2eSlogwang 	if (status->status < 0)
3212bfe3f2eSlogwang 		return;
3222bfe3f2eSlogwang 	if (atoi(tokens[1]) == INVALID_SPI)
3232bfe3f2eSlogwang 		return;
3242bfe3f2eSlogwang 	rule->spi = atoi(tokens[1]);
325*2d9fd380Sjfb8856606 	rule->portid = UINT16_MAX;
3264418919fSjohnjiang 	ips = ipsec_get_primary_session(rule);
3272bfe3f2eSlogwang 
3282bfe3f2eSlogwang 	for (ti = 2; ti < n_tokens; ti++) {
3292bfe3f2eSlogwang 		if (strcmp(tokens[ti], "mode") == 0) {
3302bfe3f2eSlogwang 			APP_CHECK_PRESENCE(mode_p, tokens[ti], status);
3312bfe3f2eSlogwang 			if (status->status < 0)
3322bfe3f2eSlogwang 				return;
3332bfe3f2eSlogwang 
3342bfe3f2eSlogwang 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
3352bfe3f2eSlogwang 			if (status->status < 0)
3362bfe3f2eSlogwang 				return;
3372bfe3f2eSlogwang 
338*2d9fd380Sjfb8856606 			if (strcmp(tokens[ti], "ipv4-tunnel") == 0) {
339*2d9fd380Sjfb8856606 				sa_cnt->nb_v4++;
3402bfe3f2eSlogwang 				rule->flags = IP4_TUNNEL;
341*2d9fd380Sjfb8856606 			} else if (strcmp(tokens[ti], "ipv6-tunnel") == 0) {
342*2d9fd380Sjfb8856606 				sa_cnt->nb_v6++;
3432bfe3f2eSlogwang 				rule->flags = IP6_TUNNEL;
344*2d9fd380Sjfb8856606 			} else if (strcmp(tokens[ti], "transport") == 0) {
345*2d9fd380Sjfb8856606 				sa_cnt->nb_v4++;
346*2d9fd380Sjfb8856606 				sa_cnt->nb_v6++;
3472bfe3f2eSlogwang 				rule->flags = TRANSPORT;
348*2d9fd380Sjfb8856606 			} else {
3492bfe3f2eSlogwang 				APP_CHECK(0, status, "unrecognized "
3502bfe3f2eSlogwang 					"input \"%s\"", tokens[ti]);
3512bfe3f2eSlogwang 				return;
3522bfe3f2eSlogwang 			}
3532bfe3f2eSlogwang 
3542bfe3f2eSlogwang 			mode_p = 1;
3552bfe3f2eSlogwang 			continue;
3562bfe3f2eSlogwang 		}
3572bfe3f2eSlogwang 
3582bfe3f2eSlogwang 		if (strcmp(tokens[ti], "cipher_algo") == 0) {
3592bfe3f2eSlogwang 			const struct supported_cipher_algo *algo;
3602bfe3f2eSlogwang 			uint32_t key_len;
3612bfe3f2eSlogwang 
3622bfe3f2eSlogwang 			APP_CHECK_PRESENCE(cipher_algo_p, tokens[ti],
3632bfe3f2eSlogwang 				status);
3642bfe3f2eSlogwang 			if (status->status < 0)
3652bfe3f2eSlogwang 				return;
3662bfe3f2eSlogwang 
3672bfe3f2eSlogwang 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
3682bfe3f2eSlogwang 			if (status->status < 0)
3692bfe3f2eSlogwang 				return;
3702bfe3f2eSlogwang 
3712bfe3f2eSlogwang 			algo = find_match_cipher_algo(tokens[ti]);
3722bfe3f2eSlogwang 
3732bfe3f2eSlogwang 			APP_CHECK(algo != NULL, status, "unrecognized "
3742bfe3f2eSlogwang 				"input \"%s\"", tokens[ti]);
3752bfe3f2eSlogwang 
3764418919fSjohnjiang 			if (status->status < 0)
3774418919fSjohnjiang 				return;
3784418919fSjohnjiang 
3792bfe3f2eSlogwang 			rule->cipher_algo = algo->algo;
3802bfe3f2eSlogwang 			rule->block_size = algo->block_size;
3812bfe3f2eSlogwang 			rule->iv_len = algo->iv_len;
3822bfe3f2eSlogwang 			rule->cipher_key_len = algo->key_len;
3832bfe3f2eSlogwang 
3842bfe3f2eSlogwang 			/* for NULL algorithm, no cipher key required */
3852bfe3f2eSlogwang 			if (rule->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
3862bfe3f2eSlogwang 				cipher_algo_p = 1;
3872bfe3f2eSlogwang 				continue;
3882bfe3f2eSlogwang 			}
3892bfe3f2eSlogwang 
3902bfe3f2eSlogwang 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
3912bfe3f2eSlogwang 			if (status->status < 0)
3922bfe3f2eSlogwang 				return;
3932bfe3f2eSlogwang 
3942bfe3f2eSlogwang 			APP_CHECK(strcmp(tokens[ti], "cipher_key") == 0,
3952bfe3f2eSlogwang 				status, "unrecognized input \"%s\", "
3962bfe3f2eSlogwang 				"expect \"cipher_key\"", tokens[ti]);
3972bfe3f2eSlogwang 			if (status->status < 0)
3982bfe3f2eSlogwang 				return;
3992bfe3f2eSlogwang 
4002bfe3f2eSlogwang 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
4012bfe3f2eSlogwang 			if (status->status < 0)
4022bfe3f2eSlogwang 				return;
4032bfe3f2eSlogwang 
4042bfe3f2eSlogwang 			key_len = parse_key_string(tokens[ti],
4052bfe3f2eSlogwang 				rule->cipher_key);
4062bfe3f2eSlogwang 			APP_CHECK(key_len == rule->cipher_key_len, status,
4072bfe3f2eSlogwang 				"unrecognized input \"%s\"", tokens[ti]);
4082bfe3f2eSlogwang 			if (status->status < 0)
4092bfe3f2eSlogwang 				return;
4102bfe3f2eSlogwang 
411d30ea906Sjfb8856606 			if (algo->algo == RTE_CRYPTO_CIPHER_AES_CBC ||
412d30ea906Sjfb8856606 				algo->algo == RTE_CRYPTO_CIPHER_3DES_CBC)
4132bfe3f2eSlogwang 				rule->salt = (uint32_t)rte_rand();
4142bfe3f2eSlogwang 
4152bfe3f2eSlogwang 			if (algo->algo == RTE_CRYPTO_CIPHER_AES_CTR) {
4162bfe3f2eSlogwang 				key_len -= 4;
4172bfe3f2eSlogwang 				rule->cipher_key_len = key_len;
4182bfe3f2eSlogwang 				memcpy(&rule->salt,
4192bfe3f2eSlogwang 					&rule->cipher_key[key_len], 4);
4202bfe3f2eSlogwang 			}
4212bfe3f2eSlogwang 
4222bfe3f2eSlogwang 			cipher_algo_p = 1;
4232bfe3f2eSlogwang 			continue;
4242bfe3f2eSlogwang 		}
4252bfe3f2eSlogwang 
4262bfe3f2eSlogwang 		if (strcmp(tokens[ti], "auth_algo") == 0) {
4272bfe3f2eSlogwang 			const struct supported_auth_algo *algo;
4282bfe3f2eSlogwang 			uint32_t key_len;
4292bfe3f2eSlogwang 
4302bfe3f2eSlogwang 			APP_CHECK_PRESENCE(auth_algo_p, tokens[ti],
4312bfe3f2eSlogwang 				status);
4322bfe3f2eSlogwang 			if (status->status < 0)
4332bfe3f2eSlogwang 				return;
4342bfe3f2eSlogwang 
4352bfe3f2eSlogwang 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
4362bfe3f2eSlogwang 			if (status->status < 0)
4372bfe3f2eSlogwang 				return;
4382bfe3f2eSlogwang 
4392bfe3f2eSlogwang 			algo = find_match_auth_algo(tokens[ti]);
4402bfe3f2eSlogwang 			APP_CHECK(algo != NULL, status, "unrecognized "
4412bfe3f2eSlogwang 				"input \"%s\"", tokens[ti]);
4422bfe3f2eSlogwang 
4434418919fSjohnjiang 			if (status->status < 0)
4444418919fSjohnjiang 				return;
4454418919fSjohnjiang 
4462bfe3f2eSlogwang 			rule->auth_algo = algo->algo;
4472bfe3f2eSlogwang 			rule->auth_key_len = algo->key_len;
4482bfe3f2eSlogwang 			rule->digest_len = algo->digest_len;
4492bfe3f2eSlogwang 
4502bfe3f2eSlogwang 			/* NULL algorithm and combined algos do not
4512bfe3f2eSlogwang 			 * require auth key
4522bfe3f2eSlogwang 			 */
4532bfe3f2eSlogwang 			if (algo->key_not_req) {
4542bfe3f2eSlogwang 				auth_algo_p = 1;
4552bfe3f2eSlogwang 				continue;
4562bfe3f2eSlogwang 			}
4572bfe3f2eSlogwang 
4582bfe3f2eSlogwang 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
4592bfe3f2eSlogwang 			if (status->status < 0)
4602bfe3f2eSlogwang 				return;
4612bfe3f2eSlogwang 
4622bfe3f2eSlogwang 			APP_CHECK(strcmp(tokens[ti], "auth_key") == 0,
4632bfe3f2eSlogwang 				status, "unrecognized input \"%s\", "
4642bfe3f2eSlogwang 				"expect \"auth_key\"", tokens[ti]);
4652bfe3f2eSlogwang 			if (status->status < 0)
4662bfe3f2eSlogwang 				return;
4672bfe3f2eSlogwang 
4682bfe3f2eSlogwang 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
4692bfe3f2eSlogwang 			if (status->status < 0)
4702bfe3f2eSlogwang 				return;
4712bfe3f2eSlogwang 
4722bfe3f2eSlogwang 			key_len = parse_key_string(tokens[ti],
4732bfe3f2eSlogwang 				rule->auth_key);
4742bfe3f2eSlogwang 			APP_CHECK(key_len == rule->auth_key_len, status,
4752bfe3f2eSlogwang 				"unrecognized input \"%s\"", tokens[ti]);
4762bfe3f2eSlogwang 			if (status->status < 0)
4772bfe3f2eSlogwang 				return;
4782bfe3f2eSlogwang 
4792bfe3f2eSlogwang 			auth_algo_p = 1;
4802bfe3f2eSlogwang 			continue;
4812bfe3f2eSlogwang 		}
4822bfe3f2eSlogwang 
4832bfe3f2eSlogwang 		if (strcmp(tokens[ti], "aead_algo") == 0) {
4842bfe3f2eSlogwang 			const struct supported_aead_algo *algo;
4852bfe3f2eSlogwang 			uint32_t key_len;
4862bfe3f2eSlogwang 
4872bfe3f2eSlogwang 			APP_CHECK_PRESENCE(aead_algo_p, tokens[ti],
4882bfe3f2eSlogwang 				status);
4892bfe3f2eSlogwang 			if (status->status < 0)
4902bfe3f2eSlogwang 				return;
4912bfe3f2eSlogwang 
4922bfe3f2eSlogwang 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
4932bfe3f2eSlogwang 			if (status->status < 0)
4942bfe3f2eSlogwang 				return;
4952bfe3f2eSlogwang 
4962bfe3f2eSlogwang 			algo = find_match_aead_algo(tokens[ti]);
4972bfe3f2eSlogwang 
4982bfe3f2eSlogwang 			APP_CHECK(algo != NULL, status, "unrecognized "
4992bfe3f2eSlogwang 				"input \"%s\"", tokens[ti]);
5002bfe3f2eSlogwang 
5014418919fSjohnjiang 			if (status->status < 0)
5024418919fSjohnjiang 				return;
5034418919fSjohnjiang 
5042bfe3f2eSlogwang 			rule->aead_algo = algo->algo;
5052bfe3f2eSlogwang 			rule->cipher_key_len = algo->key_len;
5062bfe3f2eSlogwang 			rule->digest_len = algo->digest_len;
5072bfe3f2eSlogwang 			rule->aad_len = algo->aad_len;
5082bfe3f2eSlogwang 			rule->block_size = algo->block_size;
5092bfe3f2eSlogwang 			rule->iv_len = algo->iv_len;
5102bfe3f2eSlogwang 
5112bfe3f2eSlogwang 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
5122bfe3f2eSlogwang 			if (status->status < 0)
5132bfe3f2eSlogwang 				return;
5142bfe3f2eSlogwang 
5152bfe3f2eSlogwang 			APP_CHECK(strcmp(tokens[ti], "aead_key") == 0,
5162bfe3f2eSlogwang 				status, "unrecognized input \"%s\", "
5172bfe3f2eSlogwang 				"expect \"aead_key\"", tokens[ti]);
5182bfe3f2eSlogwang 			if (status->status < 0)
5192bfe3f2eSlogwang 				return;
5202bfe3f2eSlogwang 
5212bfe3f2eSlogwang 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
5222bfe3f2eSlogwang 			if (status->status < 0)
5232bfe3f2eSlogwang 				return;
5242bfe3f2eSlogwang 
5252bfe3f2eSlogwang 			key_len = parse_key_string(tokens[ti],
5262bfe3f2eSlogwang 				rule->cipher_key);
5272bfe3f2eSlogwang 			APP_CHECK(key_len == rule->cipher_key_len, status,
5282bfe3f2eSlogwang 				"unrecognized input \"%s\"", tokens[ti]);
5292bfe3f2eSlogwang 			if (status->status < 0)
5302bfe3f2eSlogwang 				return;
5312bfe3f2eSlogwang 
5322bfe3f2eSlogwang 			key_len -= 4;
5332bfe3f2eSlogwang 			rule->cipher_key_len = key_len;
5342bfe3f2eSlogwang 			memcpy(&rule->salt,
5352bfe3f2eSlogwang 				&rule->cipher_key[key_len], 4);
5362bfe3f2eSlogwang 
5372bfe3f2eSlogwang 			aead_algo_p = 1;
5382bfe3f2eSlogwang 			continue;
5392bfe3f2eSlogwang 		}
5402bfe3f2eSlogwang 
5412bfe3f2eSlogwang 		if (strcmp(tokens[ti], "src") == 0) {
5422bfe3f2eSlogwang 			APP_CHECK_PRESENCE(src_p, tokens[ti], status);
5432bfe3f2eSlogwang 			if (status->status < 0)
5442bfe3f2eSlogwang 				return;
5452bfe3f2eSlogwang 
5462bfe3f2eSlogwang 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
5472bfe3f2eSlogwang 			if (status->status < 0)
5482bfe3f2eSlogwang 				return;
5492bfe3f2eSlogwang 
5504b05018fSfengbojiang 			if (IS_IP4_TUNNEL(rule->flags)) {
5512bfe3f2eSlogwang 				struct in_addr ip;
5522bfe3f2eSlogwang 
5532bfe3f2eSlogwang 				APP_CHECK(parse_ipv4_addr(tokens[ti],
5542bfe3f2eSlogwang 					&ip, NULL) == 0, status,
5552bfe3f2eSlogwang 					"unrecognized input \"%s\", "
5562bfe3f2eSlogwang 					"expect valid ipv4 addr",
5572bfe3f2eSlogwang 					tokens[ti]);
5582bfe3f2eSlogwang 				if (status->status < 0)
5592bfe3f2eSlogwang 					return;
5602bfe3f2eSlogwang 				rule->src.ip.ip4 = rte_bswap32(
5612bfe3f2eSlogwang 					(uint32_t)ip.s_addr);
5624b05018fSfengbojiang 			} else if (IS_IP6_TUNNEL(rule->flags)) {
5632bfe3f2eSlogwang 				struct in6_addr ip;
5642bfe3f2eSlogwang 
5652bfe3f2eSlogwang 				APP_CHECK(parse_ipv6_addr(tokens[ti], &ip,
5662bfe3f2eSlogwang 					NULL) == 0, status,
5672bfe3f2eSlogwang 					"unrecognized input \"%s\", "
5682bfe3f2eSlogwang 					"expect valid ipv6 addr",
5692bfe3f2eSlogwang 					tokens[ti]);
5702bfe3f2eSlogwang 				if (status->status < 0)
5712bfe3f2eSlogwang 					return;
5722bfe3f2eSlogwang 				memcpy(rule->src.ip.ip6.ip6_b,
5732bfe3f2eSlogwang 					ip.s6_addr, 16);
5744b05018fSfengbojiang 			} else if (IS_TRANSPORT(rule->flags)) {
5752bfe3f2eSlogwang 				APP_CHECK(0, status, "unrecognized input "
5762bfe3f2eSlogwang 					"\"%s\"", tokens[ti]);
5772bfe3f2eSlogwang 				return;
5782bfe3f2eSlogwang 			}
5792bfe3f2eSlogwang 
5802bfe3f2eSlogwang 			src_p = 1;
5812bfe3f2eSlogwang 			continue;
5822bfe3f2eSlogwang 		}
5832bfe3f2eSlogwang 
5842bfe3f2eSlogwang 		if (strcmp(tokens[ti], "dst") == 0) {
5852bfe3f2eSlogwang 			APP_CHECK_PRESENCE(dst_p, tokens[ti], status);
5862bfe3f2eSlogwang 			if (status->status < 0)
5872bfe3f2eSlogwang 				return;
5882bfe3f2eSlogwang 
5892bfe3f2eSlogwang 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
5902bfe3f2eSlogwang 			if (status->status < 0)
5912bfe3f2eSlogwang 				return;
5922bfe3f2eSlogwang 
5934b05018fSfengbojiang 			if (IS_IP4_TUNNEL(rule->flags)) {
5942bfe3f2eSlogwang 				struct in_addr ip;
5952bfe3f2eSlogwang 
5962bfe3f2eSlogwang 				APP_CHECK(parse_ipv4_addr(tokens[ti],
5972bfe3f2eSlogwang 					&ip, NULL) == 0, status,
5982bfe3f2eSlogwang 					"unrecognized input \"%s\", "
5992bfe3f2eSlogwang 					"expect valid ipv4 addr",
6002bfe3f2eSlogwang 					tokens[ti]);
6012bfe3f2eSlogwang 				if (status->status < 0)
6022bfe3f2eSlogwang 					return;
6032bfe3f2eSlogwang 				rule->dst.ip.ip4 = rte_bswap32(
6042bfe3f2eSlogwang 					(uint32_t)ip.s_addr);
6054b05018fSfengbojiang 			} else if (IS_IP6_TUNNEL(rule->flags)) {
6062bfe3f2eSlogwang 				struct in6_addr ip;
6072bfe3f2eSlogwang 
6082bfe3f2eSlogwang 				APP_CHECK(parse_ipv6_addr(tokens[ti], &ip,
6092bfe3f2eSlogwang 					NULL) == 0, status,
6102bfe3f2eSlogwang 					"unrecognized input \"%s\", "
6112bfe3f2eSlogwang 					"expect valid ipv6 addr",
6122bfe3f2eSlogwang 					tokens[ti]);
6132bfe3f2eSlogwang 				if (status->status < 0)
6142bfe3f2eSlogwang 					return;
6152bfe3f2eSlogwang 				memcpy(rule->dst.ip.ip6.ip6_b, ip.s6_addr, 16);
6164b05018fSfengbojiang 			} else if (IS_TRANSPORT(rule->flags)) {
6172bfe3f2eSlogwang 				APP_CHECK(0, status, "unrecognized "
6182bfe3f2eSlogwang 					"input \"%s\"",	tokens[ti]);
6192bfe3f2eSlogwang 				return;
6202bfe3f2eSlogwang 			}
6212bfe3f2eSlogwang 
6222bfe3f2eSlogwang 			dst_p = 1;
6232bfe3f2eSlogwang 			continue;
6242bfe3f2eSlogwang 		}
6252bfe3f2eSlogwang 
6262bfe3f2eSlogwang 		if (strcmp(tokens[ti], "type") == 0) {
6272bfe3f2eSlogwang 			APP_CHECK_PRESENCE(type_p, tokens[ti], status);
6282bfe3f2eSlogwang 			if (status->status < 0)
6292bfe3f2eSlogwang 				return;
6302bfe3f2eSlogwang 
6312bfe3f2eSlogwang 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
6322bfe3f2eSlogwang 			if (status->status < 0)
6332bfe3f2eSlogwang 				return;
6342bfe3f2eSlogwang 
6352bfe3f2eSlogwang 			if (strcmp(tokens[ti], "inline-crypto-offload") == 0)
6364418919fSjohnjiang 				ips->type =
6372bfe3f2eSlogwang 					RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO;
6382bfe3f2eSlogwang 			else if (strcmp(tokens[ti],
6392bfe3f2eSlogwang 					"inline-protocol-offload") == 0)
6404418919fSjohnjiang 				ips->type =
6412bfe3f2eSlogwang 				RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL;
6422bfe3f2eSlogwang 			else if (strcmp(tokens[ti],
6432bfe3f2eSlogwang 					"lookaside-protocol-offload") == 0)
6444418919fSjohnjiang 				ips->type =
6452bfe3f2eSlogwang 				RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL;
6462bfe3f2eSlogwang 			else if (strcmp(tokens[ti], "no-offload") == 0)
6474418919fSjohnjiang 				ips->type = RTE_SECURITY_ACTION_TYPE_NONE;
648*2d9fd380Sjfb8856606 			else if (strcmp(tokens[ti], "cpu-crypto") == 0)
649*2d9fd380Sjfb8856606 				ips->type = RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO;
6502bfe3f2eSlogwang 			else {
6512bfe3f2eSlogwang 				APP_CHECK(0, status, "Invalid input \"%s\"",
6522bfe3f2eSlogwang 						tokens[ti]);
6532bfe3f2eSlogwang 				return;
6542bfe3f2eSlogwang 			}
6552bfe3f2eSlogwang 
6562bfe3f2eSlogwang 			type_p = 1;
6572bfe3f2eSlogwang 			continue;
6582bfe3f2eSlogwang 		}
6592bfe3f2eSlogwang 
6602bfe3f2eSlogwang 		if (strcmp(tokens[ti], "port_id") == 0) {
6612bfe3f2eSlogwang 			APP_CHECK_PRESENCE(portid_p, tokens[ti], status);
6622bfe3f2eSlogwang 			if (status->status < 0)
6632bfe3f2eSlogwang 				return;
6642bfe3f2eSlogwang 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
6652bfe3f2eSlogwang 			if (status->status < 0)
6662bfe3f2eSlogwang 				return;
667*2d9fd380Sjfb8856606 			if (rule->portid == UINT16_MAX)
6682bfe3f2eSlogwang 				rule->portid = atoi(tokens[ti]);
669*2d9fd380Sjfb8856606 			else if (rule->portid != atoi(tokens[ti])) {
670*2d9fd380Sjfb8856606 				APP_CHECK(0, status,
671*2d9fd380Sjfb8856606 					"portid %s not matching with already assigned portid %u",
672*2d9fd380Sjfb8856606 					tokens[ti], rule->portid);
6732bfe3f2eSlogwang 				return;
674*2d9fd380Sjfb8856606 			}
6752bfe3f2eSlogwang 			portid_p = 1;
6762bfe3f2eSlogwang 			continue;
6772bfe3f2eSlogwang 		}
6782bfe3f2eSlogwang 
6794418919fSjohnjiang 		if (strcmp(tokens[ti], "fallback") == 0) {
6804418919fSjohnjiang 			struct rte_ipsec_session *fb;
6814418919fSjohnjiang 
6824418919fSjohnjiang 			APP_CHECK(app_sa_prm.enable, status, "Fallback session "
6834418919fSjohnjiang 				"not allowed for legacy mode.");
6844418919fSjohnjiang 			if (status->status < 0)
6854418919fSjohnjiang 				return;
6864418919fSjohnjiang 			APP_CHECK(ips->type ==
6874418919fSjohnjiang 				RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO, status,
6884418919fSjohnjiang 				"Fallback session allowed if primary session "
6894418919fSjohnjiang 				"is of type inline-crypto-offload only.");
6904418919fSjohnjiang 			if (status->status < 0)
6914418919fSjohnjiang 				return;
6924418919fSjohnjiang 			APP_CHECK(rule->direction ==
6934418919fSjohnjiang 				RTE_SECURITY_IPSEC_SA_DIR_INGRESS, status,
6944418919fSjohnjiang 				"Fallback session not allowed for egress "
6954418919fSjohnjiang 				"rule");
6964418919fSjohnjiang 			if (status->status < 0)
6974418919fSjohnjiang 				return;
6984418919fSjohnjiang 			APP_CHECK_PRESENCE(fallback_p, tokens[ti], status);
6994418919fSjohnjiang 			if (status->status < 0)
7004418919fSjohnjiang 				return;
7014418919fSjohnjiang 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
7024418919fSjohnjiang 			if (status->status < 0)
7034418919fSjohnjiang 				return;
7044418919fSjohnjiang 			fb = ipsec_get_fallback_session(rule);
705*2d9fd380Sjfb8856606 			if (strcmp(tokens[ti], "lookaside-none") == 0)
7064418919fSjohnjiang 				fb->type = RTE_SECURITY_ACTION_TYPE_NONE;
707*2d9fd380Sjfb8856606 			else if (strcmp(tokens[ti], "cpu-crypto") == 0)
708*2d9fd380Sjfb8856606 				fb->type = RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO;
709*2d9fd380Sjfb8856606 			else {
7104418919fSjohnjiang 				APP_CHECK(0, status, "unrecognized fallback "
7114418919fSjohnjiang 					"type %s.", tokens[ti]);
7124418919fSjohnjiang 				return;
7134418919fSjohnjiang 			}
7144418919fSjohnjiang 
7154418919fSjohnjiang 			rule->fallback_sessions = 1;
716*2d9fd380Sjfb8856606 			nb_crypto_sessions++;
7174418919fSjohnjiang 			fallback_p = 1;
7184418919fSjohnjiang 			continue;
7194418919fSjohnjiang 		}
720*2d9fd380Sjfb8856606 		if (strcmp(tokens[ti], "flow-direction") == 0) {
721*2d9fd380Sjfb8856606 			switch (ips->type) {
722*2d9fd380Sjfb8856606 			case RTE_SECURITY_ACTION_TYPE_NONE:
723*2d9fd380Sjfb8856606 			case RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO:
724*2d9fd380Sjfb8856606 				rule->fdir_flag = 1;
725*2d9fd380Sjfb8856606 				INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
726*2d9fd380Sjfb8856606 				if (status->status < 0)
727*2d9fd380Sjfb8856606 					return;
728*2d9fd380Sjfb8856606 				if (rule->portid == UINT16_MAX)
729*2d9fd380Sjfb8856606 					rule->portid = atoi(tokens[ti]);
730*2d9fd380Sjfb8856606 				else if (rule->portid != atoi(tokens[ti])) {
731*2d9fd380Sjfb8856606 					APP_CHECK(0, status,
732*2d9fd380Sjfb8856606 						"portid %s not matching with already assigned portid %u",
733*2d9fd380Sjfb8856606 						tokens[ti], rule->portid);
734*2d9fd380Sjfb8856606 					return;
735*2d9fd380Sjfb8856606 				}
736*2d9fd380Sjfb8856606 				INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
737*2d9fd380Sjfb8856606 				if (status->status < 0)
738*2d9fd380Sjfb8856606 					return;
739*2d9fd380Sjfb8856606 				rule->fdir_qid = atoi(tokens[ti]);
740*2d9fd380Sjfb8856606 				/* validating portid and queueid */
741*2d9fd380Sjfb8856606 				status_p = check_flow_params(rule->portid,
742*2d9fd380Sjfb8856606 						rule->fdir_qid);
743*2d9fd380Sjfb8856606 				if (status_p < 0) {
744*2d9fd380Sjfb8856606 					printf("port id %u / queue id %u is "
745*2d9fd380Sjfb8856606 						"not valid\n", rule->portid,
746*2d9fd380Sjfb8856606 						 rule->fdir_qid);
747*2d9fd380Sjfb8856606 				}
748*2d9fd380Sjfb8856606 				break;
749*2d9fd380Sjfb8856606 			case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO:
750*2d9fd380Sjfb8856606 			case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL:
751*2d9fd380Sjfb8856606 			case RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL:
752*2d9fd380Sjfb8856606 			default:
753*2d9fd380Sjfb8856606 				APP_CHECK(0, status,
754*2d9fd380Sjfb8856606 					"flow director not supported for security session type %d",
755*2d9fd380Sjfb8856606 					ips->type);
756*2d9fd380Sjfb8856606 				return;
757*2d9fd380Sjfb8856606 			}
758*2d9fd380Sjfb8856606 			continue;
759*2d9fd380Sjfb8856606 		}
7604418919fSjohnjiang 
7612bfe3f2eSlogwang 		/* unrecognizeable input */
7622bfe3f2eSlogwang 		APP_CHECK(0, status, "unrecognized input \"%s\"",
7632bfe3f2eSlogwang 			tokens[ti]);
7642bfe3f2eSlogwang 		return;
7652bfe3f2eSlogwang 	}
7662bfe3f2eSlogwang 
7672bfe3f2eSlogwang 	if (aead_algo_p) {
7682bfe3f2eSlogwang 		APP_CHECK(cipher_algo_p == 0, status,
7692bfe3f2eSlogwang 				"AEAD used, no need for cipher options");
7702bfe3f2eSlogwang 		if (status->status < 0)
7712bfe3f2eSlogwang 			return;
7722bfe3f2eSlogwang 
7732bfe3f2eSlogwang 		APP_CHECK(auth_algo_p == 0, status,
7742bfe3f2eSlogwang 				"AEAD used, no need for auth options");
7752bfe3f2eSlogwang 		if (status->status < 0)
7762bfe3f2eSlogwang 			return;
7772bfe3f2eSlogwang 	} else {
7782bfe3f2eSlogwang 		APP_CHECK(cipher_algo_p == 1, status, "missing cipher or AEAD options");
7792bfe3f2eSlogwang 		if (status->status < 0)
7802bfe3f2eSlogwang 			return;
7812bfe3f2eSlogwang 
7822bfe3f2eSlogwang 		APP_CHECK(auth_algo_p == 1, status, "missing auth or AEAD options");
7832bfe3f2eSlogwang 		if (status->status < 0)
7842bfe3f2eSlogwang 			return;
7852bfe3f2eSlogwang 	}
7862bfe3f2eSlogwang 
7872bfe3f2eSlogwang 	APP_CHECK(mode_p == 1, status, "missing mode option");
7882bfe3f2eSlogwang 	if (status->status < 0)
7892bfe3f2eSlogwang 		return;
7902bfe3f2eSlogwang 
791*2d9fd380Sjfb8856606 	if ((ips->type != RTE_SECURITY_ACTION_TYPE_NONE && ips->type !=
792*2d9fd380Sjfb8856606 			RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO) && (portid_p == 0))
7932bfe3f2eSlogwang 		printf("Missing portid option, falling back to non-offload\n");
7942bfe3f2eSlogwang 
795*2d9fd380Sjfb8856606 	if (!type_p || (!portid_p && ips->type !=
796*2d9fd380Sjfb8856606 			RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO)) {
7974418919fSjohnjiang 		ips->type = RTE_SECURITY_ACTION_TYPE_NONE;
7982bfe3f2eSlogwang 	}
7992bfe3f2eSlogwang 
800*2d9fd380Sjfb8856606 	nb_crypto_sessions++;
8012bfe3f2eSlogwang 	*ri = *ri + 1;
8022bfe3f2eSlogwang }
8032bfe3f2eSlogwang 
8041646932aSjfb8856606 static void
print_one_sa_rule(const struct ipsec_sa * sa,int inbound)8052bfe3f2eSlogwang print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
8062bfe3f2eSlogwang {
8072bfe3f2eSlogwang 	uint32_t i;
8082bfe3f2eSlogwang 	uint8_t a, b, c, d;
8094418919fSjohnjiang 	const struct rte_ipsec_session *ips;
8104418919fSjohnjiang 	const struct rte_ipsec_session *fallback_ips;
8112bfe3f2eSlogwang 
8122bfe3f2eSlogwang 	printf("\tspi_%s(%3u):", inbound?"in":"out", sa->spi);
8132bfe3f2eSlogwang 
8142bfe3f2eSlogwang 	for (i = 0; i < RTE_DIM(cipher_algos); i++) {
815d30ea906Sjfb8856606 		if (cipher_algos[i].algo == sa->cipher_algo &&
816d30ea906Sjfb8856606 				cipher_algos[i].key_len == sa->cipher_key_len) {
8172bfe3f2eSlogwang 			printf("%s ", cipher_algos[i].keyword);
8182bfe3f2eSlogwang 			break;
8192bfe3f2eSlogwang 		}
8202bfe3f2eSlogwang 	}
8212bfe3f2eSlogwang 
8222bfe3f2eSlogwang 	for (i = 0; i < RTE_DIM(auth_algos); i++) {
8232bfe3f2eSlogwang 		if (auth_algos[i].algo == sa->auth_algo) {
8242bfe3f2eSlogwang 			printf("%s ", auth_algos[i].keyword);
8252bfe3f2eSlogwang 			break;
8262bfe3f2eSlogwang 		}
8272bfe3f2eSlogwang 	}
8282bfe3f2eSlogwang 
8292bfe3f2eSlogwang 	for (i = 0; i < RTE_DIM(aead_algos); i++) {
830*2d9fd380Sjfb8856606 		if (aead_algos[i].algo == sa->aead_algo &&
831*2d9fd380Sjfb8856606 				aead_algos[i].key_len-4 == sa->cipher_key_len) {
8322bfe3f2eSlogwang 			printf("%s ", aead_algos[i].keyword);
8332bfe3f2eSlogwang 			break;
8342bfe3f2eSlogwang 		}
8352bfe3f2eSlogwang 	}
8362bfe3f2eSlogwang 
8372bfe3f2eSlogwang 	printf("mode:");
8382bfe3f2eSlogwang 
8394b05018fSfengbojiang 	switch (WITHOUT_TRANSPORT_VERSION(sa->flags)) {
8402bfe3f2eSlogwang 	case IP4_TUNNEL:
8412bfe3f2eSlogwang 		printf("IP4Tunnel ");
8422bfe3f2eSlogwang 		uint32_t_to_char(sa->src.ip.ip4, &a, &b, &c, &d);
8432bfe3f2eSlogwang 		printf("%hhu.%hhu.%hhu.%hhu ", d, c, b, a);
8442bfe3f2eSlogwang 		uint32_t_to_char(sa->dst.ip.ip4, &a, &b, &c, &d);
8452bfe3f2eSlogwang 		printf("%hhu.%hhu.%hhu.%hhu", d, c, b, a);
8462bfe3f2eSlogwang 		break;
8472bfe3f2eSlogwang 	case IP6_TUNNEL:
8482bfe3f2eSlogwang 		printf("IP6Tunnel ");
8492bfe3f2eSlogwang 		for (i = 0; i < 16; i++) {
8502bfe3f2eSlogwang 			if (i % 2 && i != 15)
8512bfe3f2eSlogwang 				printf("%.2x:", sa->src.ip.ip6.ip6_b[i]);
8522bfe3f2eSlogwang 			else
8532bfe3f2eSlogwang 				printf("%.2x", sa->src.ip.ip6.ip6_b[i]);
8542bfe3f2eSlogwang 		}
8552bfe3f2eSlogwang 		printf(" ");
8562bfe3f2eSlogwang 		for (i = 0; i < 16; i++) {
8572bfe3f2eSlogwang 			if (i % 2 && i != 15)
8582bfe3f2eSlogwang 				printf("%.2x:", sa->dst.ip.ip6.ip6_b[i]);
8592bfe3f2eSlogwang 			else
8602bfe3f2eSlogwang 				printf("%.2x", sa->dst.ip.ip6.ip6_b[i]);
8612bfe3f2eSlogwang 		}
8622bfe3f2eSlogwang 		break;
8632bfe3f2eSlogwang 	case TRANSPORT:
8642bfe3f2eSlogwang 		printf("Transport ");
8652bfe3f2eSlogwang 		break;
8662bfe3f2eSlogwang 	}
8674418919fSjohnjiang 
8684418919fSjohnjiang 	ips = &sa->sessions[IPSEC_SESSION_PRIMARY];
8691646932aSjfb8856606 	printf(" type:");
8704418919fSjohnjiang 	switch (ips->type) {
8711646932aSjfb8856606 	case RTE_SECURITY_ACTION_TYPE_NONE:
8721646932aSjfb8856606 		printf("no-offload ");
8731646932aSjfb8856606 		break;
8741646932aSjfb8856606 	case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO:
8751646932aSjfb8856606 		printf("inline-crypto-offload ");
8761646932aSjfb8856606 		break;
8771646932aSjfb8856606 	case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL:
8781646932aSjfb8856606 		printf("inline-protocol-offload ");
8791646932aSjfb8856606 		break;
8801646932aSjfb8856606 	case RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL:
8811646932aSjfb8856606 		printf("lookaside-protocol-offload ");
8821646932aSjfb8856606 		break;
883*2d9fd380Sjfb8856606 	case RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO:
884*2d9fd380Sjfb8856606 		printf("cpu-crypto-accelerated ");
885*2d9fd380Sjfb8856606 		break;
8861646932aSjfb8856606 	}
8874418919fSjohnjiang 
8884418919fSjohnjiang 	fallback_ips = &sa->sessions[IPSEC_SESSION_FALLBACK];
8894418919fSjohnjiang 	if (fallback_ips != NULL && sa->fallback_sessions > 0) {
8904418919fSjohnjiang 		printf("inline fallback: ");
891*2d9fd380Sjfb8856606 		switch (fallback_ips->type) {
892*2d9fd380Sjfb8856606 		case RTE_SECURITY_ACTION_TYPE_NONE:
8934418919fSjohnjiang 			printf("lookaside-none");
894*2d9fd380Sjfb8856606 			break;
895*2d9fd380Sjfb8856606 		case RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO:
896*2d9fd380Sjfb8856606 			printf("cpu-crypto-accelerated");
897*2d9fd380Sjfb8856606 			break;
898*2d9fd380Sjfb8856606 		default:
8994418919fSjohnjiang 			printf("invalid");
900*2d9fd380Sjfb8856606 			break;
9014418919fSjohnjiang 		}
902*2d9fd380Sjfb8856606 	}
903*2d9fd380Sjfb8856606 	if (sa->fdir_flag == 1)
904*2d9fd380Sjfb8856606 		printf("flow-direction port %d queue %d", sa->portid,
905*2d9fd380Sjfb8856606 				sa->fdir_qid);
906*2d9fd380Sjfb8856606 
9072bfe3f2eSlogwang 	printf("\n");
9082bfe3f2eSlogwang }
909a9643ea8Slogwang 
910a9643ea8Slogwang static struct sa_ctx *
sa_create(const char * name,int32_t socket_id,uint32_t nb_sa)911*2d9fd380Sjfb8856606 sa_create(const char *name, int32_t socket_id, uint32_t nb_sa)
912a9643ea8Slogwang {
913a9643ea8Slogwang 	char s[PATH_MAX];
914a9643ea8Slogwang 	struct sa_ctx *sa_ctx;
915a9643ea8Slogwang 	uint32_t mz_size;
916a9643ea8Slogwang 	const struct rte_memzone *mz;
917a9643ea8Slogwang 
918a9643ea8Slogwang 	snprintf(s, sizeof(s), "%s_%u", name, socket_id);
919a9643ea8Slogwang 
920*2d9fd380Sjfb8856606 	/* Create SA context */
9211646932aSjfb8856606 	printf("Creating SA context with %u maximum entries on socket %d\n",
922*2d9fd380Sjfb8856606 			nb_sa, socket_id);
923a9643ea8Slogwang 
924*2d9fd380Sjfb8856606 	mz_size = sizeof(struct ipsec_xf) * nb_sa;
925a9643ea8Slogwang 	mz = rte_memzone_reserve(s, mz_size, socket_id,
926a9643ea8Slogwang 			RTE_MEMZONE_1GB | RTE_MEMZONE_SIZE_HINT_ONLY);
927a9643ea8Slogwang 	if (mz == NULL) {
928*2d9fd380Sjfb8856606 		printf("Failed to allocate SA XFORM memory\n");
9294b05018fSfengbojiang 		rte_errno = ENOMEM;
930a9643ea8Slogwang 		return NULL;
931a9643ea8Slogwang 	}
932a9643ea8Slogwang 
933*2d9fd380Sjfb8856606 	sa_ctx = rte_zmalloc(NULL, sizeof(struct sa_ctx) +
934*2d9fd380Sjfb8856606 		sizeof(struct ipsec_sa) * nb_sa, RTE_CACHE_LINE_SIZE);
935*2d9fd380Sjfb8856606 
936*2d9fd380Sjfb8856606 	if (sa_ctx == NULL) {
937*2d9fd380Sjfb8856606 		printf("Failed to allocate SA CTX memory\n");
938*2d9fd380Sjfb8856606 		rte_errno = ENOMEM;
939*2d9fd380Sjfb8856606 		rte_memzone_free(mz);
940*2d9fd380Sjfb8856606 		return NULL;
941*2d9fd380Sjfb8856606 	}
942*2d9fd380Sjfb8856606 
943*2d9fd380Sjfb8856606 	sa_ctx->xf = (struct ipsec_xf *)mz->addr;
944*2d9fd380Sjfb8856606 	sa_ctx->nb_sa = nb_sa;
945a9643ea8Slogwang 
946a9643ea8Slogwang 	return sa_ctx;
947a9643ea8Slogwang }
948a9643ea8Slogwang 
949a9643ea8Slogwang static int
check_eth_dev_caps(uint16_t portid,uint32_t inbound)9502bfe3f2eSlogwang check_eth_dev_caps(uint16_t portid, uint32_t inbound)
9512bfe3f2eSlogwang {
9522bfe3f2eSlogwang 	struct rte_eth_dev_info dev_info;
9534418919fSjohnjiang 	int retval;
9542bfe3f2eSlogwang 
9554418919fSjohnjiang 	retval = rte_eth_dev_info_get(portid, &dev_info);
9564418919fSjohnjiang 	if (retval != 0) {
9574418919fSjohnjiang 		RTE_LOG(ERR, IPSEC,
9584418919fSjohnjiang 			"Error during getting device (port %u) info: %s\n",
9594418919fSjohnjiang 			portid, strerror(-retval));
9604418919fSjohnjiang 
9614418919fSjohnjiang 		return retval;
9624418919fSjohnjiang 	}
9632bfe3f2eSlogwang 
9642bfe3f2eSlogwang 	if (inbound) {
9652bfe3f2eSlogwang 		if ((dev_info.rx_offload_capa &
9662bfe3f2eSlogwang 				DEV_RX_OFFLOAD_SECURITY) == 0) {
9672bfe3f2eSlogwang 			RTE_LOG(WARNING, PORT,
9682bfe3f2eSlogwang 				"hardware RX IPSec offload is not supported\n");
9692bfe3f2eSlogwang 			return -EINVAL;
9702bfe3f2eSlogwang 		}
9712bfe3f2eSlogwang 
9722bfe3f2eSlogwang 	} else { /* outbound */
9732bfe3f2eSlogwang 		if ((dev_info.tx_offload_capa &
9742bfe3f2eSlogwang 				DEV_TX_OFFLOAD_SECURITY) == 0) {
9752bfe3f2eSlogwang 			RTE_LOG(WARNING, PORT,
9762bfe3f2eSlogwang 				"hardware TX IPSec offload is not supported\n");
9772bfe3f2eSlogwang 			return -EINVAL;
9782bfe3f2eSlogwang 		}
9792bfe3f2eSlogwang 	}
9802bfe3f2eSlogwang 	return 0;
9812bfe3f2eSlogwang }
9822bfe3f2eSlogwang 
9834b05018fSfengbojiang /*
9844b05018fSfengbojiang  * Helper function, tries to determine next_proto for SPI
9854b05018fSfengbojiang  * by searching though SP rules.
9864b05018fSfengbojiang  */
9874b05018fSfengbojiang static int
get_spi_proto(uint32_t spi,enum rte_security_ipsec_sa_direction dir,struct ip_addr ip_addr[2],uint32_t mask[2])9884b05018fSfengbojiang get_spi_proto(uint32_t spi, enum rte_security_ipsec_sa_direction dir,
9894b05018fSfengbojiang 		struct ip_addr ip_addr[2], uint32_t mask[2])
9904b05018fSfengbojiang {
9914b05018fSfengbojiang 	int32_t rc4, rc6;
9924b05018fSfengbojiang 
9934b05018fSfengbojiang 	rc4 = sp4_spi_present(spi, dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS,
9944b05018fSfengbojiang 				ip_addr, mask);
9954b05018fSfengbojiang 	rc6 = sp6_spi_present(spi, dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS,
9964b05018fSfengbojiang 				ip_addr, mask);
9974b05018fSfengbojiang 
9984b05018fSfengbojiang 	if (rc4 >= 0) {
9994b05018fSfengbojiang 		if (rc6 >= 0) {
10004b05018fSfengbojiang 			RTE_LOG(ERR, IPSEC,
10014b05018fSfengbojiang 				"%s: SPI %u used simultaeously by "
10024b05018fSfengbojiang 				"IPv4(%d) and IPv6 (%d) SP rules\n",
10034b05018fSfengbojiang 				__func__, spi, rc4, rc6);
10044b05018fSfengbojiang 			return -EINVAL;
10054b05018fSfengbojiang 		} else
10064b05018fSfengbojiang 			return IPPROTO_IPIP;
10074b05018fSfengbojiang 	} else if (rc6 < 0) {
10084b05018fSfengbojiang 		RTE_LOG(ERR, IPSEC,
10094b05018fSfengbojiang 			"%s: SPI %u is not used by any SP rule\n",
10104b05018fSfengbojiang 			__func__, spi);
10114b05018fSfengbojiang 		return -EINVAL;
10124b05018fSfengbojiang 	} else
10134b05018fSfengbojiang 		return IPPROTO_IPV6;
10144b05018fSfengbojiang }
10154b05018fSfengbojiang 
10164b05018fSfengbojiang /*
10174b05018fSfengbojiang  * Helper function for getting source and destination IP addresses
10184b05018fSfengbojiang  * from SP. Needed for inline crypto transport mode, as addresses are not
10194b05018fSfengbojiang  * provided in config file for that mode. It checks if SP for current SA exists,
10204b05018fSfengbojiang  * and based on what type of protocol is returned, it stores appropriate
10214b05018fSfengbojiang  * addresses got from SP into SA.
10224b05018fSfengbojiang  */
10234b05018fSfengbojiang static int
sa_add_address_inline_crypto(struct ipsec_sa * sa)10244b05018fSfengbojiang sa_add_address_inline_crypto(struct ipsec_sa *sa)
10254b05018fSfengbojiang {
10264b05018fSfengbojiang 	int protocol;
10274b05018fSfengbojiang 	struct ip_addr ip_addr[2];
10284b05018fSfengbojiang 	uint32_t mask[2];
10294b05018fSfengbojiang 
10304b05018fSfengbojiang 	protocol = get_spi_proto(sa->spi, sa->direction, ip_addr, mask);
10314b05018fSfengbojiang 	if (protocol < 0)
10324b05018fSfengbojiang 		return protocol;
10334b05018fSfengbojiang 	else if (protocol == IPPROTO_IPIP) {
10344b05018fSfengbojiang 		sa->flags |= IP4_TRANSPORT;
10354b05018fSfengbojiang 		if (mask[0] == IP4_FULL_MASK &&
10364b05018fSfengbojiang 				mask[1] == IP4_FULL_MASK &&
10374b05018fSfengbojiang 				ip_addr[0].ip.ip4 != 0 &&
10384b05018fSfengbojiang 				ip_addr[1].ip.ip4 != 0) {
10394b05018fSfengbojiang 
10404b05018fSfengbojiang 			sa->src.ip.ip4 = ip_addr[0].ip.ip4;
10414b05018fSfengbojiang 			sa->dst.ip.ip4 = ip_addr[1].ip.ip4;
10424b05018fSfengbojiang 		} else {
10434b05018fSfengbojiang 			RTE_LOG(ERR, IPSEC,
10444b05018fSfengbojiang 			"%s: No valid address or mask entry in"
10454b05018fSfengbojiang 			" IPv4 SP rule for SPI %u\n",
10464b05018fSfengbojiang 			__func__, sa->spi);
10474b05018fSfengbojiang 			return -EINVAL;
10484b05018fSfengbojiang 		}
10494b05018fSfengbojiang 	} else if (protocol == IPPROTO_IPV6) {
10504b05018fSfengbojiang 		sa->flags |= IP6_TRANSPORT;
10514b05018fSfengbojiang 		if (mask[0] == IP6_FULL_MASK &&
10524b05018fSfengbojiang 				mask[1] == IP6_FULL_MASK &&
10534b05018fSfengbojiang 				(ip_addr[0].ip.ip6.ip6[0] != 0 ||
10544b05018fSfengbojiang 				ip_addr[0].ip.ip6.ip6[1] != 0) &&
10554b05018fSfengbojiang 				(ip_addr[1].ip.ip6.ip6[0] != 0 ||
10564b05018fSfengbojiang 				ip_addr[1].ip.ip6.ip6[1] != 0)) {
10574b05018fSfengbojiang 
10584b05018fSfengbojiang 			sa->src.ip.ip6 = ip_addr[0].ip.ip6;
10594b05018fSfengbojiang 			sa->dst.ip.ip6 = ip_addr[1].ip.ip6;
10604b05018fSfengbojiang 		} else {
10614b05018fSfengbojiang 			RTE_LOG(ERR, IPSEC,
10624b05018fSfengbojiang 			"%s: No valid address or mask entry in"
10634b05018fSfengbojiang 			" IPv6 SP rule for SPI %u\n",
10644b05018fSfengbojiang 			__func__, sa->spi);
10654b05018fSfengbojiang 			return -EINVAL;
10664b05018fSfengbojiang 		}
10674b05018fSfengbojiang 	}
10684b05018fSfengbojiang 	return 0;
10694b05018fSfengbojiang }
10702bfe3f2eSlogwang 
10712bfe3f2eSlogwang static int
sa_add_rules(struct sa_ctx * sa_ctx,const struct ipsec_sa entries[],uint32_t nb_entries,uint32_t inbound,struct socket_ctx * skt_ctx)1072a9643ea8Slogwang sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
10734418919fSjohnjiang 		uint32_t nb_entries, uint32_t inbound,
10744418919fSjohnjiang 		struct socket_ctx *skt_ctx)
1075a9643ea8Slogwang {
1076a9643ea8Slogwang 	struct ipsec_sa *sa;
1077a9643ea8Slogwang 	uint32_t i, idx;
10784418919fSjohnjiang 	uint16_t iv_length, aad_length;
10794b05018fSfengbojiang 	int inline_status;
10804418919fSjohnjiang 	int32_t rc;
10814418919fSjohnjiang 	struct rte_ipsec_session *ips;
10824418919fSjohnjiang 
10834418919fSjohnjiang 	/* for ESN upper 32 bits of SQN also need to be part of AAD */
10844418919fSjohnjiang 	aad_length = (app_sa_prm.enable_esn != 0) ? sizeof(uint32_t) : 0;
1085a9643ea8Slogwang 
1086a9643ea8Slogwang 	for (i = 0; i < nb_entries; i++) {
1087*2d9fd380Sjfb8856606 		idx = i;
1088a9643ea8Slogwang 		sa = &sa_ctx->sa[idx];
1089a9643ea8Slogwang 		if (sa->spi != 0) {
1090a9643ea8Slogwang 			printf("Index %u already in use by SPI %u\n",
1091a9643ea8Slogwang 					idx, sa->spi);
1092a9643ea8Slogwang 			return -EINVAL;
1093a9643ea8Slogwang 		}
1094a9643ea8Slogwang 		*sa = entries[i];
1095*2d9fd380Sjfb8856606 
1096*2d9fd380Sjfb8856606 		if (inbound) {
1097*2d9fd380Sjfb8856606 			rc = ipsec_sad_add(&sa_ctx->sad, sa);
1098*2d9fd380Sjfb8856606 			if (rc != 0)
1099*2d9fd380Sjfb8856606 				return rc;
1100*2d9fd380Sjfb8856606 		}
1101*2d9fd380Sjfb8856606 
1102a9643ea8Slogwang 		sa->seq = 0;
11034418919fSjohnjiang 		ips = ipsec_get_primary_session(sa);
1104a9643ea8Slogwang 
11054418919fSjohnjiang 		if (ips->type == RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL ||
11064418919fSjohnjiang 			ips->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
11072bfe3f2eSlogwang 			if (check_eth_dev_caps(sa->portid, inbound))
11082bfe3f2eSlogwang 				return -EINVAL;
11092bfe3f2eSlogwang 		}
11102bfe3f2eSlogwang 
11114b05018fSfengbojiang 		switch (WITHOUT_TRANSPORT_VERSION(sa->flags)) {
1112a9643ea8Slogwang 		case IP4_TUNNEL:
1113a9643ea8Slogwang 			sa->src.ip.ip4 = rte_cpu_to_be_32(sa->src.ip.ip4);
1114a9643ea8Slogwang 			sa->dst.ip.ip4 = rte_cpu_to_be_32(sa->dst.ip.ip4);
11154b05018fSfengbojiang 			break;
11164b05018fSfengbojiang 		case TRANSPORT:
11174418919fSjohnjiang 			if (ips->type ==
11184b05018fSfengbojiang 				RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
11194b05018fSfengbojiang 				inline_status =
11204b05018fSfengbojiang 					sa_add_address_inline_crypto(sa);
11214b05018fSfengbojiang 				if (inline_status < 0)
11224b05018fSfengbojiang 					return inline_status;
11234b05018fSfengbojiang 			}
11244b05018fSfengbojiang 			break;
1125a9643ea8Slogwang 		}
1126a9643ea8Slogwang 
11272bfe3f2eSlogwang 		if (sa->aead_algo == RTE_CRYPTO_AEAD_AES_GCM) {
11284418919fSjohnjiang 			iv_length = 12;
11292bfe3f2eSlogwang 
11302bfe3f2eSlogwang 			sa_ctx->xf[idx].a.type = RTE_CRYPTO_SYM_XFORM_AEAD;
11312bfe3f2eSlogwang 			sa_ctx->xf[idx].a.aead.algo = sa->aead_algo;
11322bfe3f2eSlogwang 			sa_ctx->xf[idx].a.aead.key.data = sa->cipher_key;
11332bfe3f2eSlogwang 			sa_ctx->xf[idx].a.aead.key.length =
11342bfe3f2eSlogwang 				sa->cipher_key_len;
11352bfe3f2eSlogwang 			sa_ctx->xf[idx].a.aead.op = (inbound == 1) ?
11362bfe3f2eSlogwang 				RTE_CRYPTO_AEAD_OP_DECRYPT :
11372bfe3f2eSlogwang 				RTE_CRYPTO_AEAD_OP_ENCRYPT;
11382bfe3f2eSlogwang 			sa_ctx->xf[idx].a.next = NULL;
11392bfe3f2eSlogwang 			sa_ctx->xf[idx].a.aead.iv.offset = IV_OFFSET;
11402bfe3f2eSlogwang 			sa_ctx->xf[idx].a.aead.iv.length = iv_length;
11412bfe3f2eSlogwang 			sa_ctx->xf[idx].a.aead.aad_length =
11424418919fSjohnjiang 				sa->aad_len + aad_length;
11432bfe3f2eSlogwang 			sa_ctx->xf[idx].a.aead.digest_length =
11442bfe3f2eSlogwang 				sa->digest_len;
11452bfe3f2eSlogwang 
11462bfe3f2eSlogwang 			sa->xforms = &sa_ctx->xf[idx].a;
11472bfe3f2eSlogwang 		} else {
11482bfe3f2eSlogwang 			switch (sa->cipher_algo) {
11492bfe3f2eSlogwang 			case RTE_CRYPTO_CIPHER_NULL:
1150d30ea906Sjfb8856606 			case RTE_CRYPTO_CIPHER_3DES_CBC:
11512bfe3f2eSlogwang 			case RTE_CRYPTO_CIPHER_AES_CBC:
11522bfe3f2eSlogwang 				iv_length = sa->iv_len;
11532bfe3f2eSlogwang 				break;
11542bfe3f2eSlogwang 			case RTE_CRYPTO_CIPHER_AES_CTR:
11552bfe3f2eSlogwang 				iv_length = 16;
11562bfe3f2eSlogwang 				break;
11572bfe3f2eSlogwang 			default:
11582bfe3f2eSlogwang 				RTE_LOG(ERR, IPSEC_ESP,
11592bfe3f2eSlogwang 						"unsupported cipher algorithm %u\n",
11602bfe3f2eSlogwang 						sa->cipher_algo);
11612bfe3f2eSlogwang 				return -EINVAL;
11622bfe3f2eSlogwang 			}
11632bfe3f2eSlogwang 
1164a9643ea8Slogwang 			if (inbound) {
11652bfe3f2eSlogwang 				sa_ctx->xf[idx].b.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
11662bfe3f2eSlogwang 				sa_ctx->xf[idx].b.cipher.algo = sa->cipher_algo;
11672bfe3f2eSlogwang 				sa_ctx->xf[idx].b.cipher.key.data = sa->cipher_key;
11682bfe3f2eSlogwang 				sa_ctx->xf[idx].b.cipher.key.length =
11692bfe3f2eSlogwang 					sa->cipher_key_len;
11702bfe3f2eSlogwang 				sa_ctx->xf[idx].b.cipher.op =
11712bfe3f2eSlogwang 					RTE_CRYPTO_CIPHER_OP_DECRYPT;
11722bfe3f2eSlogwang 				sa_ctx->xf[idx].b.next = NULL;
11732bfe3f2eSlogwang 				sa_ctx->xf[idx].b.cipher.iv.offset = IV_OFFSET;
11742bfe3f2eSlogwang 				sa_ctx->xf[idx].b.cipher.iv.length = iv_length;
11752bfe3f2eSlogwang 
11762bfe3f2eSlogwang 				sa_ctx->xf[idx].a.type = RTE_CRYPTO_SYM_XFORM_AUTH;
11772bfe3f2eSlogwang 				sa_ctx->xf[idx].a.auth.algo = sa->auth_algo;
11782bfe3f2eSlogwang 				sa_ctx->xf[idx].a.auth.key.data = sa->auth_key;
11792bfe3f2eSlogwang 				sa_ctx->xf[idx].a.auth.key.length =
11802bfe3f2eSlogwang 					sa->auth_key_len;
11812bfe3f2eSlogwang 				sa_ctx->xf[idx].a.auth.digest_length =
11822bfe3f2eSlogwang 					sa->digest_len;
11832bfe3f2eSlogwang 				sa_ctx->xf[idx].a.auth.op =
11842bfe3f2eSlogwang 					RTE_CRYPTO_AUTH_OP_VERIFY;
1185a9643ea8Slogwang 			} else { /* outbound */
11862bfe3f2eSlogwang 				sa_ctx->xf[idx].a.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
11872bfe3f2eSlogwang 				sa_ctx->xf[idx].a.cipher.algo = sa->cipher_algo;
11882bfe3f2eSlogwang 				sa_ctx->xf[idx].a.cipher.key.data = sa->cipher_key;
11892bfe3f2eSlogwang 				sa_ctx->xf[idx].a.cipher.key.length =
11902bfe3f2eSlogwang 					sa->cipher_key_len;
11912bfe3f2eSlogwang 				sa_ctx->xf[idx].a.cipher.op =
11922bfe3f2eSlogwang 					RTE_CRYPTO_CIPHER_OP_ENCRYPT;
11932bfe3f2eSlogwang 				sa_ctx->xf[idx].a.next = NULL;
11942bfe3f2eSlogwang 				sa_ctx->xf[idx].a.cipher.iv.offset = IV_OFFSET;
11952bfe3f2eSlogwang 				sa_ctx->xf[idx].a.cipher.iv.length = iv_length;
11962bfe3f2eSlogwang 
11972bfe3f2eSlogwang 				sa_ctx->xf[idx].b.type = RTE_CRYPTO_SYM_XFORM_AUTH;
11982bfe3f2eSlogwang 				sa_ctx->xf[idx].b.auth.algo = sa->auth_algo;
11992bfe3f2eSlogwang 				sa_ctx->xf[idx].b.auth.key.data = sa->auth_key;
12002bfe3f2eSlogwang 				sa_ctx->xf[idx].b.auth.key.length =
12012bfe3f2eSlogwang 					sa->auth_key_len;
12022bfe3f2eSlogwang 				sa_ctx->xf[idx].b.auth.digest_length =
12032bfe3f2eSlogwang 					sa->digest_len;
12042bfe3f2eSlogwang 				sa_ctx->xf[idx].b.auth.op =
12052bfe3f2eSlogwang 					RTE_CRYPTO_AUTH_OP_GENERATE;
1206a9643ea8Slogwang 			}
12072bfe3f2eSlogwang 
1208a9643ea8Slogwang 			sa_ctx->xf[idx].a.next = &sa_ctx->xf[idx].b;
1209a9643ea8Slogwang 			sa_ctx->xf[idx].b.next = NULL;
1210a9643ea8Slogwang 			sa->xforms = &sa_ctx->xf[idx].a;
12114418919fSjohnjiang 		}
12124418919fSjohnjiang 
12134418919fSjohnjiang 		if (ips->type ==
12144418919fSjohnjiang 			RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL ||
12154418919fSjohnjiang 			ips->type ==
12164418919fSjohnjiang 			RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
12174418919fSjohnjiang 			rc = create_inline_session(skt_ctx, sa, ips);
12184418919fSjohnjiang 			if (rc != 0) {
12194418919fSjohnjiang 				RTE_LOG(ERR, IPSEC_ESP,
12204418919fSjohnjiang 					"create_inline_session() failed\n");
12214418919fSjohnjiang 				return -EINVAL;
12224418919fSjohnjiang 			}
12234418919fSjohnjiang 		}
12242bfe3f2eSlogwang 
1225*2d9fd380Sjfb8856606 		if (sa->fdir_flag && inbound) {
1226*2d9fd380Sjfb8856606 			rc = create_ipsec_esp_flow(sa);
1227*2d9fd380Sjfb8856606 			if (rc != 0)
1228*2d9fd380Sjfb8856606 				RTE_LOG(ERR, IPSEC_ESP,
1229*2d9fd380Sjfb8856606 					"create_ipsec_esp_flow() failed\n");
1230*2d9fd380Sjfb8856606 		}
12312bfe3f2eSlogwang 		print_one_sa_rule(sa, inbound);
12322bfe3f2eSlogwang 	}
1233a9643ea8Slogwang 
1234a9643ea8Slogwang 	return 0;
1235a9643ea8Slogwang }
1236a9643ea8Slogwang 
1237a9643ea8Slogwang static inline int
sa_out_add_rules(struct sa_ctx * sa_ctx,const struct ipsec_sa entries[],uint32_t nb_entries,struct socket_ctx * skt_ctx)1238a9643ea8Slogwang sa_out_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
12394418919fSjohnjiang 		uint32_t nb_entries, struct socket_ctx *skt_ctx)
1240a9643ea8Slogwang {
12414418919fSjohnjiang 	return sa_add_rules(sa_ctx, entries, nb_entries, 0, skt_ctx);
1242a9643ea8Slogwang }
1243a9643ea8Slogwang 
1244a9643ea8Slogwang static inline int
sa_in_add_rules(struct sa_ctx * sa_ctx,const struct ipsec_sa entries[],uint32_t nb_entries,struct socket_ctx * skt_ctx)1245a9643ea8Slogwang sa_in_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
12464418919fSjohnjiang 		uint32_t nb_entries, struct socket_ctx *skt_ctx)
1247a9643ea8Slogwang {
12484418919fSjohnjiang 	return sa_add_rules(sa_ctx, entries, nb_entries, 1, skt_ctx);
12494418919fSjohnjiang }
12504418919fSjohnjiang 
12514418919fSjohnjiang /*
12524418919fSjohnjiang  * helper function, fills parameters that are identical for all SAs
12534418919fSjohnjiang  */
12544418919fSjohnjiang static void
fill_ipsec_app_sa_prm(struct rte_ipsec_sa_prm * prm,const struct app_sa_prm * app_prm)12554418919fSjohnjiang fill_ipsec_app_sa_prm(struct rte_ipsec_sa_prm *prm,
12564418919fSjohnjiang 	const struct app_sa_prm *app_prm)
12574418919fSjohnjiang {
12584418919fSjohnjiang 	memset(prm, 0, sizeof(*prm));
12594418919fSjohnjiang 
12604418919fSjohnjiang 	prm->flags = app_prm->flags;
12614418919fSjohnjiang 	prm->ipsec_xform.options.esn = app_prm->enable_esn;
12624418919fSjohnjiang 	prm->ipsec_xform.replay_win_sz = app_prm->window_size;
12634418919fSjohnjiang }
12644418919fSjohnjiang 
12654418919fSjohnjiang static int
fill_ipsec_sa_prm(struct rte_ipsec_sa_prm * prm,const struct ipsec_sa * ss,const struct rte_ipv4_hdr * v4,struct rte_ipv6_hdr * v6)12664418919fSjohnjiang fill_ipsec_sa_prm(struct rte_ipsec_sa_prm *prm, const struct ipsec_sa *ss,
12674418919fSjohnjiang 	const struct rte_ipv4_hdr *v4, struct rte_ipv6_hdr *v6)
12684418919fSjohnjiang {
12694418919fSjohnjiang 	int32_t rc;
12704418919fSjohnjiang 
12714418919fSjohnjiang 	/*
12724418919fSjohnjiang 	 * Try to get SPI next proto by searching that SPI in SPD.
12734418919fSjohnjiang 	 * probably not the optimal way, but there seems nothing
12744418919fSjohnjiang 	 * better right now.
12754418919fSjohnjiang 	 */
12764418919fSjohnjiang 	rc = get_spi_proto(ss->spi, ss->direction, NULL, NULL);
12774418919fSjohnjiang 	if (rc < 0)
12784418919fSjohnjiang 		return rc;
12794418919fSjohnjiang 
12804418919fSjohnjiang 	fill_ipsec_app_sa_prm(prm, &app_sa_prm);
12814418919fSjohnjiang 	prm->userdata = (uintptr_t)ss;
12824418919fSjohnjiang 
12834418919fSjohnjiang 	/* setup ipsec xform */
12844418919fSjohnjiang 	prm->ipsec_xform.spi = ss->spi;
12854418919fSjohnjiang 	prm->ipsec_xform.salt = ss->salt;
12864418919fSjohnjiang 	prm->ipsec_xform.direction = ss->direction;
12874418919fSjohnjiang 	prm->ipsec_xform.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP;
12884418919fSjohnjiang 	prm->ipsec_xform.mode = (IS_TRANSPORT(ss->flags)) ?
12894418919fSjohnjiang 		RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT :
12904418919fSjohnjiang 		RTE_SECURITY_IPSEC_SA_MODE_TUNNEL;
12914418919fSjohnjiang 	prm->ipsec_xform.options.ecn = 1;
12924418919fSjohnjiang 	prm->ipsec_xform.options.copy_dscp = 1;
12934418919fSjohnjiang 
12944418919fSjohnjiang 	if (IS_IP4_TUNNEL(ss->flags)) {
12954418919fSjohnjiang 		prm->ipsec_xform.tunnel.type = RTE_SECURITY_IPSEC_TUNNEL_IPV4;
12964418919fSjohnjiang 		prm->tun.hdr_len = sizeof(*v4);
12974418919fSjohnjiang 		prm->tun.next_proto = rc;
12984418919fSjohnjiang 		prm->tun.hdr = v4;
12994418919fSjohnjiang 	} else if (IS_IP6_TUNNEL(ss->flags)) {
13004418919fSjohnjiang 		prm->ipsec_xform.tunnel.type = RTE_SECURITY_IPSEC_TUNNEL_IPV6;
13014418919fSjohnjiang 		prm->tun.hdr_len = sizeof(*v6);
13024418919fSjohnjiang 		prm->tun.next_proto = rc;
13034418919fSjohnjiang 		prm->tun.hdr = v6;
13044418919fSjohnjiang 	} else {
13054418919fSjohnjiang 		/* transport mode */
13064418919fSjohnjiang 		prm->trs.proto = rc;
13074418919fSjohnjiang 	}
13084418919fSjohnjiang 
13094418919fSjohnjiang 	/* setup crypto section */
13104418919fSjohnjiang 	prm->crypto_xform = ss->xforms;
13114418919fSjohnjiang 	return 0;
13124418919fSjohnjiang }
13134418919fSjohnjiang 
13144418919fSjohnjiang static int
fill_ipsec_session(struct rte_ipsec_session * ss,struct rte_ipsec_sa * sa)13154418919fSjohnjiang fill_ipsec_session(struct rte_ipsec_session *ss, struct rte_ipsec_sa *sa)
13164418919fSjohnjiang {
13174418919fSjohnjiang 	int32_t rc = 0;
13184418919fSjohnjiang 
13194418919fSjohnjiang 	ss->sa = sa;
13204418919fSjohnjiang 
13214418919fSjohnjiang 	if (ss->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO ||
13224418919fSjohnjiang 		ss->type == RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) {
13234418919fSjohnjiang 		if (ss->security.ses != NULL) {
13244418919fSjohnjiang 			rc = rte_ipsec_session_prepare(ss);
13254418919fSjohnjiang 			if (rc != 0)
13264418919fSjohnjiang 				memset(ss, 0, sizeof(*ss));
13274418919fSjohnjiang 		}
13284418919fSjohnjiang 	}
13294418919fSjohnjiang 
13304418919fSjohnjiang 	return rc;
13314418919fSjohnjiang }
13324418919fSjohnjiang 
13334418919fSjohnjiang /*
13344418919fSjohnjiang  * Initialise related rte_ipsec_sa object.
13354418919fSjohnjiang  */
13364418919fSjohnjiang static int
ipsec_sa_init(struct ipsec_sa * lsa,struct rte_ipsec_sa * sa,uint32_t sa_size)13374418919fSjohnjiang ipsec_sa_init(struct ipsec_sa *lsa, struct rte_ipsec_sa *sa, uint32_t sa_size)
13384418919fSjohnjiang {
13394418919fSjohnjiang 	int rc;
13404418919fSjohnjiang 	struct rte_ipsec_sa_prm prm;
13414418919fSjohnjiang 	struct rte_ipsec_session *ips;
13424418919fSjohnjiang 	struct rte_ipv4_hdr v4  = {
13434418919fSjohnjiang 		.version_ihl = IPVERSION << 4 |
13444418919fSjohnjiang 			sizeof(v4) / RTE_IPV4_IHL_MULTIPLIER,
13454418919fSjohnjiang 		.time_to_live = IPDEFTTL,
13464418919fSjohnjiang 		.next_proto_id = IPPROTO_ESP,
13474418919fSjohnjiang 		.src_addr = lsa->src.ip.ip4,
13484418919fSjohnjiang 		.dst_addr = lsa->dst.ip.ip4,
13494418919fSjohnjiang 	};
13504418919fSjohnjiang 	struct rte_ipv6_hdr v6 = {
13514418919fSjohnjiang 		.vtc_flow = htonl(IP6_VERSION << 28),
13524418919fSjohnjiang 		.proto = IPPROTO_ESP,
13534418919fSjohnjiang 	};
13544418919fSjohnjiang 
13554418919fSjohnjiang 	if (IS_IP6_TUNNEL(lsa->flags)) {
13564418919fSjohnjiang 		memcpy(v6.src_addr, lsa->src.ip.ip6.ip6_b, sizeof(v6.src_addr));
13574418919fSjohnjiang 		memcpy(v6.dst_addr, lsa->dst.ip.ip6.ip6_b, sizeof(v6.dst_addr));
13584418919fSjohnjiang 	}
13594418919fSjohnjiang 
13604418919fSjohnjiang 	rc = fill_ipsec_sa_prm(&prm, lsa, &v4, &v6);
13614418919fSjohnjiang 	if (rc == 0)
13624418919fSjohnjiang 		rc = rte_ipsec_sa_init(sa, &prm, sa_size);
13634418919fSjohnjiang 	if (rc < 0)
13644418919fSjohnjiang 		return rc;
13654418919fSjohnjiang 
13664418919fSjohnjiang 	/* init primary processing session */
13674418919fSjohnjiang 	ips = ipsec_get_primary_session(lsa);
13684418919fSjohnjiang 	rc = fill_ipsec_session(ips, sa);
13694418919fSjohnjiang 	if (rc != 0)
13704418919fSjohnjiang 		return rc;
13714418919fSjohnjiang 
13724418919fSjohnjiang 	/* init inline fallback processing session */
13734418919fSjohnjiang 	if (lsa->fallback_sessions == 1)
13744418919fSjohnjiang 		rc = fill_ipsec_session(ipsec_get_fallback_session(lsa), sa);
13754418919fSjohnjiang 
13764418919fSjohnjiang 	return rc;
13774418919fSjohnjiang }
13784418919fSjohnjiang 
13794418919fSjohnjiang /*
13804418919fSjohnjiang  * Allocate space and init rte_ipsec_sa strcutures,
13814418919fSjohnjiang  * one per session.
13824418919fSjohnjiang  */
13834418919fSjohnjiang static int
ipsec_satbl_init(struct sa_ctx * ctx,uint32_t nb_ent,int32_t socket)1384*2d9fd380Sjfb8856606 ipsec_satbl_init(struct sa_ctx *ctx, uint32_t nb_ent, int32_t socket)
13854418919fSjohnjiang {
13864418919fSjohnjiang 	int32_t rc, sz;
13874418919fSjohnjiang 	uint32_t i, idx;
13884418919fSjohnjiang 	size_t tsz;
13894418919fSjohnjiang 	struct rte_ipsec_sa *sa;
13904418919fSjohnjiang 	struct ipsec_sa *lsa;
13914418919fSjohnjiang 	struct rte_ipsec_sa_prm prm;
13924418919fSjohnjiang 
13934418919fSjohnjiang 	/* determine SA size */
1394*2d9fd380Sjfb8856606 	idx = 0;
13954418919fSjohnjiang 	fill_ipsec_sa_prm(&prm, ctx->sa + idx, NULL, NULL);
13964418919fSjohnjiang 	sz = rte_ipsec_sa_size(&prm);
13974418919fSjohnjiang 	if (sz < 0) {
13984418919fSjohnjiang 		RTE_LOG(ERR, IPSEC, "%s(%p, %u, %d): "
13994418919fSjohnjiang 			"failed to determine SA size, error code: %d\n",
14004418919fSjohnjiang 			__func__, ctx, nb_ent, socket, sz);
14014418919fSjohnjiang 		return sz;
14024418919fSjohnjiang 	}
14034418919fSjohnjiang 
14044418919fSjohnjiang 	tsz = sz * nb_ent;
14054418919fSjohnjiang 
14064418919fSjohnjiang 	ctx->satbl = rte_zmalloc_socket(NULL, tsz, RTE_CACHE_LINE_SIZE, socket);
14074418919fSjohnjiang 	if (ctx->satbl == NULL) {
14084418919fSjohnjiang 		RTE_LOG(ERR, IPSEC,
14094418919fSjohnjiang 			"%s(%p, %u, %d): failed to allocate %zu bytes\n",
14104418919fSjohnjiang 			__func__,  ctx, nb_ent, socket, tsz);
14114418919fSjohnjiang 		return -ENOMEM;
14124418919fSjohnjiang 	}
14134418919fSjohnjiang 
14144418919fSjohnjiang 	rc = 0;
14154418919fSjohnjiang 	for (i = 0; i != nb_ent && rc == 0; i++) {
14164418919fSjohnjiang 
1417*2d9fd380Sjfb8856606 		idx = i;
14184418919fSjohnjiang 
14194418919fSjohnjiang 		sa = (struct rte_ipsec_sa *)((uintptr_t)ctx->satbl + sz * i);
14204418919fSjohnjiang 		lsa = ctx->sa + idx;
14214418919fSjohnjiang 
14224418919fSjohnjiang 		rc = ipsec_sa_init(lsa, sa, sz);
14234418919fSjohnjiang 	}
14244418919fSjohnjiang 
14254418919fSjohnjiang 	return rc;
1426a9643ea8Slogwang }
1427a9643ea8Slogwang 
1428*2d9fd380Sjfb8856606 static int
sa_cmp(const void * p,const void * q)1429*2d9fd380Sjfb8856606 sa_cmp(const void *p, const void *q)
1430*2d9fd380Sjfb8856606 {
1431*2d9fd380Sjfb8856606 	uint32_t spi1 = ((const struct ipsec_sa *)p)->spi;
1432*2d9fd380Sjfb8856606 	uint32_t spi2 = ((const struct ipsec_sa *)q)->spi;
1433*2d9fd380Sjfb8856606 
1434*2d9fd380Sjfb8856606 	return (int)(spi1 - spi2);
1435*2d9fd380Sjfb8856606 }
1436*2d9fd380Sjfb8856606 
14371646932aSjfb8856606 /*
14381646932aSjfb8856606  * Walk through all SA rules to find an SA with given SPI
14391646932aSjfb8856606  */
14401646932aSjfb8856606 int
sa_spi_present(struct sa_ctx * sa_ctx,uint32_t spi,int inbound)1441*2d9fd380Sjfb8856606 sa_spi_present(struct sa_ctx *sa_ctx, uint32_t spi, int inbound)
14421646932aSjfb8856606 {
1443*2d9fd380Sjfb8856606 	uint32_t num;
1444*2d9fd380Sjfb8856606 	struct ipsec_sa *sa;
1445*2d9fd380Sjfb8856606 	struct ipsec_sa tmpl;
14461646932aSjfb8856606 	const struct ipsec_sa *sar;
14471646932aSjfb8856606 
1448*2d9fd380Sjfb8856606 	sar = sa_ctx->sa;
1449*2d9fd380Sjfb8856606 	if (inbound != 0)
14501646932aSjfb8856606 		num = nb_sa_in;
1451*2d9fd380Sjfb8856606 	else
14521646932aSjfb8856606 		num = nb_sa_out;
14531646932aSjfb8856606 
1454*2d9fd380Sjfb8856606 	tmpl.spi = spi;
1455*2d9fd380Sjfb8856606 
1456*2d9fd380Sjfb8856606 	sa = bsearch(&tmpl, sar, num, sizeof(struct ipsec_sa), sa_cmp);
1457*2d9fd380Sjfb8856606 	if (sa != NULL)
1458*2d9fd380Sjfb8856606 		return RTE_PTR_DIFF(sa, sar) / sizeof(struct ipsec_sa);
14591646932aSjfb8856606 
14601646932aSjfb8856606 	return -ENOENT;
14611646932aSjfb8856606 }
14621646932aSjfb8856606 
1463a9643ea8Slogwang void
sa_init(struct socket_ctx * ctx,int32_t socket_id)14642bfe3f2eSlogwang sa_init(struct socket_ctx *ctx, int32_t socket_id)
1465a9643ea8Slogwang {
14664418919fSjohnjiang 	int32_t rc;
1467a9643ea8Slogwang 	const char *name;
1468a9643ea8Slogwang 
1469a9643ea8Slogwang 	if (ctx == NULL)
1470a9643ea8Slogwang 		rte_exit(EXIT_FAILURE, "NULL context.\n");
1471a9643ea8Slogwang 
1472a9643ea8Slogwang 	if (ctx->sa_in != NULL)
1473a9643ea8Slogwang 		rte_exit(EXIT_FAILURE, "Inbound SA DB for socket %u already "
1474a9643ea8Slogwang 				"initialized\n", socket_id);
1475a9643ea8Slogwang 
1476a9643ea8Slogwang 	if (ctx->sa_out != NULL)
1477a9643ea8Slogwang 		rte_exit(EXIT_FAILURE, "Outbound SA DB for socket %u already "
1478a9643ea8Slogwang 				"initialized\n", socket_id);
1479a9643ea8Slogwang 
14802bfe3f2eSlogwang 	if (nb_sa_in > 0) {
1481a9643ea8Slogwang 		name = "sa_in";
1482*2d9fd380Sjfb8856606 		ctx->sa_in = sa_create(name, socket_id, nb_sa_in);
1483a9643ea8Slogwang 		if (ctx->sa_in == NULL)
14842bfe3f2eSlogwang 			rte_exit(EXIT_FAILURE, "Error [%d] creating SA "
14852bfe3f2eSlogwang 				"context %s in socket %d\n", rte_errno,
14862bfe3f2eSlogwang 				name, socket_id);
1487a9643ea8Slogwang 
1488*2d9fd380Sjfb8856606 		rc = ipsec_sad_create(name, &ctx->sa_in->sad, socket_id,
1489*2d9fd380Sjfb8856606 				&sa_in_cnt);
1490*2d9fd380Sjfb8856606 		if (rc != 0)
1491*2d9fd380Sjfb8856606 			rte_exit(EXIT_FAILURE, "failed to init SAD\n");
1492*2d9fd380Sjfb8856606 
14934418919fSjohnjiang 		sa_in_add_rules(ctx->sa_in, sa_in, nb_sa_in, ctx);
14944418919fSjohnjiang 
14954418919fSjohnjiang 		if (app_sa_prm.enable != 0) {
1496*2d9fd380Sjfb8856606 			rc = ipsec_satbl_init(ctx->sa_in, nb_sa_in,
14974418919fSjohnjiang 				socket_id);
14984418919fSjohnjiang 			if (rc != 0)
14994418919fSjohnjiang 				rte_exit(EXIT_FAILURE,
15004418919fSjohnjiang 					"failed to init inbound SAs\n");
15014418919fSjohnjiang 		}
15022bfe3f2eSlogwang 	} else
15032bfe3f2eSlogwang 		RTE_LOG(WARNING, IPSEC, "No SA Inbound rule specified\n");
15042bfe3f2eSlogwang 
15052bfe3f2eSlogwang 	if (nb_sa_out > 0) {
1506a9643ea8Slogwang 		name = "sa_out";
1507*2d9fd380Sjfb8856606 		ctx->sa_out = sa_create(name, socket_id, nb_sa_out);
1508a9643ea8Slogwang 		if (ctx->sa_out == NULL)
15092bfe3f2eSlogwang 			rte_exit(EXIT_FAILURE, "Error [%d] creating SA "
15102bfe3f2eSlogwang 				"context %s in socket %d\n", rte_errno,
15112bfe3f2eSlogwang 				name, socket_id);
1512a9643ea8Slogwang 
15134418919fSjohnjiang 		sa_out_add_rules(ctx->sa_out, sa_out, nb_sa_out, ctx);
15144418919fSjohnjiang 
15154418919fSjohnjiang 		if (app_sa_prm.enable != 0) {
1516*2d9fd380Sjfb8856606 			rc = ipsec_satbl_init(ctx->sa_out, nb_sa_out,
15174418919fSjohnjiang 				socket_id);
15184418919fSjohnjiang 			if (rc != 0)
15194418919fSjohnjiang 				rte_exit(EXIT_FAILURE,
15204418919fSjohnjiang 					"failed to init outbound SAs\n");
15214418919fSjohnjiang 		}
15222bfe3f2eSlogwang 	} else
15232bfe3f2eSlogwang 		RTE_LOG(WARNING, IPSEC, "No SA Outbound rule "
15242bfe3f2eSlogwang 			"specified\n");
1525a9643ea8Slogwang }
1526a9643ea8Slogwang 
1527a9643ea8Slogwang int
inbound_sa_check(struct sa_ctx * sa_ctx,struct rte_mbuf * m,uint32_t sa_idx)1528a9643ea8Slogwang inbound_sa_check(struct sa_ctx *sa_ctx, struct rte_mbuf *m, uint32_t sa_idx)
1529a9643ea8Slogwang {
1530a9643ea8Slogwang 	struct ipsec_mbuf_metadata *priv;
15311646932aSjfb8856606 	struct ipsec_sa *sa;
1532a9643ea8Slogwang 
1533d30ea906Sjfb8856606 	priv = get_priv(m);
15341646932aSjfb8856606 	sa = priv->sa;
15351646932aSjfb8856606 	if (sa != NULL)
15361646932aSjfb8856606 		return (sa_ctx->sa[sa_idx].spi == sa->spi);
1537a9643ea8Slogwang 
15381646932aSjfb8856606 	RTE_LOG(ERR, IPSEC, "SA not saved in private data\n");
15391646932aSjfb8856606 	return 0;
1540a9643ea8Slogwang }
1541a9643ea8Slogwang 
1542*2d9fd380Sjfb8856606 void
inbound_sa_lookup(struct sa_ctx * sa_ctx,struct rte_mbuf * pkts[],void * sa_arr[],uint16_t nb_pkts)1543*2d9fd380Sjfb8856606 inbound_sa_lookup(struct sa_ctx *sa_ctx, struct rte_mbuf *pkts[],
1544*2d9fd380Sjfb8856606 		void *sa_arr[], uint16_t nb_pkts)
1545a9643ea8Slogwang {
1546*2d9fd380Sjfb8856606 	uint32_t i;
15474418919fSjohnjiang 	void *result_sa;
1548*2d9fd380Sjfb8856606 	struct ipsec_sa *sa;
1549a9643ea8Slogwang 
1550*2d9fd380Sjfb8856606 	sad_lookup(&sa_ctx->sad, pkts, sa_arr, nb_pkts);
1551a9643ea8Slogwang 
15524418919fSjohnjiang 	/*
15534418919fSjohnjiang 	 * Mark need for inline offload fallback on the LSB of SA pointer.
15544418919fSjohnjiang 	 * Thanks to packet grouping mechanism which ipsec_process is using
15554418919fSjohnjiang 	 * packets marked for fallback processing will form separate group.
15564418919fSjohnjiang 	 *
15574418919fSjohnjiang 	 * Because it is not safe to use SA pointer it is casted to generic
15584418919fSjohnjiang 	 * pointer to prevent from unintentional use. Use ipsec_mask_saptr
15594418919fSjohnjiang 	 * to get valid struct pointer.
15604418919fSjohnjiang 	 */
1561*2d9fd380Sjfb8856606 	for (i = 0; i < nb_pkts; i++) {
1562*2d9fd380Sjfb8856606 		if (sa_arr[i] == NULL)
1563*2d9fd380Sjfb8856606 			continue;
1564*2d9fd380Sjfb8856606 
1565*2d9fd380Sjfb8856606 		result_sa = sa = sa_arr[i];
1566*2d9fd380Sjfb8856606 		if (MBUF_NO_SEC_OFFLOAD(pkts[i]) &&
1567*2d9fd380Sjfb8856606 			sa->fallback_sessions > 0) {
15684418919fSjohnjiang 			uintptr_t intsa = (uintptr_t)sa;
15694418919fSjohnjiang 			intsa |= IPSEC_SA_OFFLOAD_FALLBACK_FLAG;
15704418919fSjohnjiang 			result_sa = (void *)intsa;
15714418919fSjohnjiang 		}
1572*2d9fd380Sjfb8856606 		sa_arr[i] = result_sa;
1573a9643ea8Slogwang 	}
1574a9643ea8Slogwang }
1575a9643ea8Slogwang 
1576a9643ea8Slogwang void
outbound_sa_lookup(struct sa_ctx * sa_ctx,uint32_t sa_idx[],void * sa[],uint16_t nb_pkts)1577a9643ea8Slogwang outbound_sa_lookup(struct sa_ctx *sa_ctx, uint32_t sa_idx[],
15784418919fSjohnjiang 		void *sa[], uint16_t nb_pkts)
1579a9643ea8Slogwang {
1580a9643ea8Slogwang 	uint32_t i;
1581a9643ea8Slogwang 
1582a9643ea8Slogwang 	for (i = 0; i < nb_pkts; i++)
1583a9643ea8Slogwang 		sa[i] = &sa_ctx->sa[sa_idx[i]];
1584a9643ea8Slogwang }
15854418919fSjohnjiang 
15864418919fSjohnjiang /*
15874418919fSjohnjiang  * Select HW offloads to be used.
15884418919fSjohnjiang  */
15894418919fSjohnjiang int
sa_check_offloads(uint16_t port_id,uint64_t * rx_offloads,uint64_t * tx_offloads)15904418919fSjohnjiang sa_check_offloads(uint16_t port_id, uint64_t *rx_offloads,
15914418919fSjohnjiang 		uint64_t *tx_offloads)
15924418919fSjohnjiang {
15934418919fSjohnjiang 	struct ipsec_sa *rule;
15944418919fSjohnjiang 	uint32_t idx_sa;
15954418919fSjohnjiang 	enum rte_security_session_action_type rule_type;
15964418919fSjohnjiang 
15974418919fSjohnjiang 	*rx_offloads = 0;
15984418919fSjohnjiang 	*tx_offloads = 0;
15994418919fSjohnjiang 
16004418919fSjohnjiang 	/* Check for inbound rules that use offloads and use this port */
16014418919fSjohnjiang 	for (idx_sa = 0; idx_sa < nb_sa_in; idx_sa++) {
16024418919fSjohnjiang 		rule = &sa_in[idx_sa];
16034418919fSjohnjiang 		rule_type = ipsec_get_action_type(rule);
16044418919fSjohnjiang 		if ((rule_type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO ||
16054418919fSjohnjiang 				rule_type ==
16064418919fSjohnjiang 				RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL)
16074418919fSjohnjiang 				&& rule->portid == port_id)
16084418919fSjohnjiang 			*rx_offloads |= DEV_RX_OFFLOAD_SECURITY;
16094418919fSjohnjiang 	}
16104418919fSjohnjiang 
16114418919fSjohnjiang 	/* Check for outbound rules that use offloads and use this port */
16124418919fSjohnjiang 	for (idx_sa = 0; idx_sa < nb_sa_out; idx_sa++) {
16134418919fSjohnjiang 		rule = &sa_out[idx_sa];
16144418919fSjohnjiang 		rule_type = ipsec_get_action_type(rule);
16154418919fSjohnjiang 		if ((rule_type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO ||
16164418919fSjohnjiang 				rule_type ==
16174418919fSjohnjiang 				RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL)
16184418919fSjohnjiang 				&& rule->portid == port_id)
16194418919fSjohnjiang 			*tx_offloads |= DEV_TX_OFFLOAD_SECURITY;
16204418919fSjohnjiang 	}
16214418919fSjohnjiang 	return 0;
16224418919fSjohnjiang }
1623*2d9fd380Sjfb8856606 
1624*2d9fd380Sjfb8856606 void
sa_sort_arr(void)1625*2d9fd380Sjfb8856606 sa_sort_arr(void)
1626*2d9fd380Sjfb8856606 {
1627*2d9fd380Sjfb8856606 	qsort(sa_in, nb_sa_in, sizeof(struct ipsec_sa), sa_cmp);
1628*2d9fd380Sjfb8856606 	qsort(sa_out, nb_sa_out, sizeof(struct ipsec_sa), sa_cmp);
1629*2d9fd380Sjfb8856606 }
1630*2d9fd380Sjfb8856606 
1631*2d9fd380Sjfb8856606 uint32_t
get_nb_crypto_sessions(void)1632*2d9fd380Sjfb8856606 get_nb_crypto_sessions(void)
1633*2d9fd380Sjfb8856606 {
1634*2d9fd380Sjfb8856606 	return nb_crypto_sessions;
1635*2d9fd380Sjfb8856606 }
1636