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