xref: /dpdk/drivers/net/nfp/nfp_ipsec.c (revision 3da59f30a23f2e795d2315f3d949e1b3e0ce0c3d)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2023 Corigine Systems, Inc.
3  * All rights reserved.
4  */
5 
6 #include <stdalign.h>
7 
8 #include "nfp_ipsec.h"
9 
10 #include <rte_cryptodev.h>
11 #include <rte_malloc.h>
12 #include <rte_security_driver.h>
13 
14 #include <ethdev_driver.h>
15 #include <ethdev_pci.h>
16 
17 #include "nfp_logs.h"
18 #include "nfp_net_common.h"
19 #include "nfp_net_ctrl.h"
20 #include "nfp_rxtx.h"
21 
22 #define NFP_UDP_ESP_PORT            4500
23 
24 static const struct rte_cryptodev_capabilities nfp_crypto_caps[] = {
25 	{
26 		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
27 		.sym = {
28 			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
29 			.auth = {
30 				.algo = RTE_CRYPTO_AUTH_MD5_HMAC,
31 				.block_size = 64,
32 				.key_size = {
33 					.min = 16,
34 					.max = 16,
35 					.increment = 0
36 				},
37 				.digest_size = {
38 					.min = 12,
39 					.max = 16,
40 					.increment = 4
41 				},
42 			},
43 		},
44 	},
45 	{
46 		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
47 		.sym = {
48 			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
49 			.auth = {
50 				.algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
51 				.block_size = 64,
52 				.key_size = {
53 					.min = 20,
54 					.max = 64,
55 					.increment = 1
56 				},
57 				.digest_size = {
58 					.min = 10,
59 					.max = 12,
60 					.increment = 2
61 				},
62 			},
63 		},
64 	},
65 	{
66 		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
67 		.sym = {
68 			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
69 			.auth = {
70 				.algo = RTE_CRYPTO_AUTH_SHA256_HMAC,
71 				.block_size = 64,
72 				.key_size = {
73 					.min = 32,
74 					.max = 32,
75 					.increment = 0
76 				},
77 				.digest_size = {
78 					.min = 12,
79 					.max = 16,
80 					.increment = 4
81 				},
82 			},
83 		},
84 	},
85 	{
86 		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
87 		.sym = {
88 			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
89 			.auth = {
90 				.algo = RTE_CRYPTO_AUTH_SHA384_HMAC,
91 				.block_size = 128,
92 				.key_size = {
93 					.min = 48,
94 					.max = 48,
95 					.increment = 0
96 				},
97 				.digest_size = {
98 					.min = 12,
99 					.max = 24,
100 					.increment = 12
101 				},
102 			},
103 		},
104 	},
105 	{
106 		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
107 		.sym = {
108 			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
109 			.auth = {
110 				.algo = RTE_CRYPTO_AUTH_SHA512_HMAC,
111 				.block_size = 128,
112 				.key_size = {
113 					.min = 64,
114 					.max = 64,
115 					.increment = 1
116 				},
117 				.digest_size = {
118 					.min = 12,
119 					.max = 32,
120 					.increment = 4
121 				},
122 			},
123 		},
124 	},
125 	{
126 		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
127 		.sym = {
128 			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
129 			.cipher = {
130 				.algo = RTE_CRYPTO_CIPHER_3DES_CBC,
131 				.block_size = 8,
132 				.key_size = {
133 					.min = 24,
134 					.max = 24,
135 					.increment = 0
136 				},
137 				.iv_size = {
138 					.min = 8,
139 					.max = 16,
140 					.increment = 8
141 				},
142 			},
143 		},
144 	},
145 	{
146 		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
147 		.sym = {
148 			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
149 			.cipher = {
150 				.algo = RTE_CRYPTO_CIPHER_AES_CBC,
151 				.block_size = 16,
152 				.key_size = {
153 					.min = 16,
154 					.max = 32,
155 					.increment = 8
156 				},
157 				.iv_size = {
158 					.min = 8,
159 					.max = 16,
160 					.increment = 8
161 				},
162 			},
163 		},
164 	},
165 	{
166 		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
167 		.sym = {
168 			.xform_type = RTE_CRYPTO_SYM_XFORM_AEAD,
169 			.aead = {
170 				.algo = RTE_CRYPTO_AEAD_AES_GCM,
171 				.block_size = 16,
172 				.key_size = {
173 					.min = 16,
174 					.max = 32,
175 					.increment = 8
176 				},
177 				.digest_size = {
178 					.min = 16,
179 					.max = 16,
180 					.increment = 0
181 				},
182 				.aad_size = {
183 					.min = 0,
184 					.max = 1024,
185 					.increment = 1
186 				},
187 				.iv_size = {
188 					.min = 8,
189 					.max = 16,
190 					.increment = 4
191 				}
192 			},
193 		},
194 	},
195 	{
196 		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
197 		.sym = {
198 			.xform_type = RTE_CRYPTO_SYM_XFORM_AEAD,
199 			.aead = {
200 				.algo = RTE_CRYPTO_AEAD_CHACHA20_POLY1305,
201 				.block_size = 16,
202 				.key_size = {
203 					.min = 32,
204 					.max = 32,
205 					.increment = 0
206 				},
207 				.digest_size = {
208 					.min = 16,
209 					.max = 16,
210 					.increment = 0
211 				},
212 				.aad_size = {
213 					.min = 0,
214 					.max = 1024,
215 					.increment = 1
216 				},
217 				.iv_size = {
218 					.min = 8,
219 					.max = 16,
220 					.increment = 4
221 				}
222 			},
223 		},
224 	},
225 	{
226 		.op = RTE_CRYPTO_OP_TYPE_UNDEFINED,
227 		.sym = {
228 			.xform_type = RTE_CRYPTO_SYM_XFORM_NOT_SPECIFIED
229 		},
230 	}
231 };
232 
233 static const struct rte_security_capability nfp_security_caps[] = {
234 	{ /* IPsec Inline Crypto Tunnel Egress */
235 		.action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
236 		.protocol = RTE_SECURITY_PROTOCOL_IPSEC,
237 		.ipsec = {
238 			.mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL,
239 			.direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS,
240 			.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
241 			.options = {
242 				.udp_encap = 1,
243 				.stats = 1,
244 				.esn = 1
245 				}
246 		},
247 		.crypto_capabilities = nfp_crypto_caps,
248 		.ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA
249 	},
250 	{ /* IPsec Inline Crypto Tunnel Ingress */
251 		.action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
252 		.protocol = RTE_SECURITY_PROTOCOL_IPSEC,
253 		.ipsec = {
254 			.mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL,
255 			.direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS,
256 			.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
257 			.options = {
258 				.udp_encap = 1,
259 				.stats = 1,
260 				.esn = 1
261 				}
262 		},
263 		.crypto_capabilities = nfp_crypto_caps
264 	},
265 	{ /* IPsec Inline Crypto Transport Egress */
266 		.action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
267 		.protocol = RTE_SECURITY_PROTOCOL_IPSEC,
268 		.ipsec = {
269 			.mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
270 			.direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS,
271 			.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
272 			.options = {
273 				.udp_encap = 1,
274 				.stats = 1,
275 				.esn = 1
276 				}
277 		},
278 		.crypto_capabilities = nfp_crypto_caps,
279 		.ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA
280 	},
281 	{ /* IPsec Inline Crypto Transport Ingress */
282 		.action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
283 		.protocol = RTE_SECURITY_PROTOCOL_IPSEC,
284 		.ipsec = {
285 			.mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
286 			.direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS,
287 			.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
288 			.options = {
289 				.udp_encap = 1,
290 				.stats = 1,
291 				.esn = 1
292 				}
293 		},
294 		.crypto_capabilities = nfp_crypto_caps
295 	},
296 	{ /* IPsec Inline Protocol Tunnel Egress */
297 		.action = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL,
298 		.protocol = RTE_SECURITY_PROTOCOL_IPSEC,
299 		.ipsec = {
300 			.mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL,
301 			.direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS,
302 			.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
303 			.options = {
304 				.udp_encap = 1,
305 				.stats = 1,
306 				.esn = 1
307 				}
308 		},
309 		.crypto_capabilities = nfp_crypto_caps,
310 		.ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA
311 	},
312 	{ /* IPsec Inline Protocol Tunnel Ingress */
313 		.action = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL,
314 		.protocol = RTE_SECURITY_PROTOCOL_IPSEC,
315 		.ipsec = {
316 			.mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL,
317 			.direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS,
318 			.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
319 			.options = {
320 				.udp_encap = 1,
321 				.stats = 1,
322 				.esn = 1
323 				}
324 		},
325 		.crypto_capabilities = nfp_crypto_caps
326 	},
327 	{ /* IPsec Inline Protocol Transport Egress */
328 		.action = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL,
329 		.protocol = RTE_SECURITY_PROTOCOL_IPSEC,
330 		.ipsec = {
331 			.mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
332 			.direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS,
333 			.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
334 			.options = {
335 				.udp_encap = 1,
336 				.stats = 1,
337 				.esn = 1
338 				}
339 		},
340 		.crypto_capabilities = nfp_crypto_caps,
341 		.ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA
342 	},
343 	{ /* IPsec Inline Protocol Transport Ingress */
344 		.action = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL,
345 		.protocol = RTE_SECURITY_PROTOCOL_IPSEC,
346 		.ipsec = {
347 			.mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
348 			.direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS,
349 			.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
350 			.options = {
351 				.udp_encap = 1,
352 				.stats = 1,
353 				.esn = 1
354 				}
355 		},
356 		.crypto_capabilities = nfp_crypto_caps
357 	},
358 	{
359 		.action = RTE_SECURITY_ACTION_TYPE_NONE
360 	}
361 };
362 
363 /* IPsec config message cmd codes */
364 enum nfp_ipsec_cfg_msg_cmd_codes {
365 	NFP_IPSEC_CFG_MSG_ADD_SA,       /**< Add a new SA */
366 	NFP_IPSEC_CFG_MSG_INV_SA,       /**< Invalidate an existing SA */
367 	NFP_IPSEC_CFG_MSG_MODIFY_SA,    /**< Modify an existing SA */
368 	NFP_IPSEC_CFG_MSG_GET_SA_STATS, /**< Report SA counters, flags, etc. */
369 	NFP_IPSEC_CFG_MSG_GET_SEQ_NUMS, /**< Allocate sequence numbers */
370 	NFP_IPSEC_CFG_MSG_LAST
371 };
372 
373 enum nfp_ipsec_cfg_msg_rsp_codes {
374 	NFP_IPSEC_CFG_MSG_OK,
375 	NFP_IPSEC_CFG_MSG_FAILED,
376 	NFP_IPSEC_CFG_MSG_SA_VALID,
377 	NFP_IPSEC_CFG_MSG_SA_HASH_ADD_FAILED,
378 	NFP_IPSEC_CFG_MSG_SA_HASH_DEL_FAILED,
379 	NFP_IPSEC_CFG_MSG_SA_INVALID_CMD
380 };
381 
382 enum nfp_ipsec_mode {
383 	NFP_IPSEC_MODE_TRANSPORT,
384 	NFP_IPSEC_MODE_TUNNEL,
385 };
386 
387 enum nfp_ipsec_protocol {
388 	NFP_IPSEC_PROTOCOL_AH,
389 	NFP_IPSEC_PROTOCOL_ESP,
390 };
391 
392 /* Cipher modes */
393 enum nfp_ipsec_cimode {
394 	NFP_IPSEC_CIMODE_ECB,
395 	NFP_IPSEC_CIMODE_CBC,
396 	NFP_IPSEC_CIMODE_CFB,
397 	NFP_IPSEC_CIMODE_OFB,
398 	NFP_IPSEC_CIMODE_CTR,
399 };
400 
401 /* Hash types */
402 enum nfp_ipsec_hash_type {
403 	NFP_IPSEC_HASH_NONE,
404 	NFP_IPSEC_HASH_MD5_96,
405 	NFP_IPSEC_HASH_SHA1_96,
406 	NFP_IPSEC_HASH_SHA256_96,
407 	NFP_IPSEC_HASH_SHA384_96,
408 	NFP_IPSEC_HASH_SHA512_96,
409 	NFP_IPSEC_HASH_MD5_128,
410 	NFP_IPSEC_HASH_SHA1_80,
411 	NFP_IPSEC_HASH_SHA256_128,
412 	NFP_IPSEC_HASH_SHA384_192,
413 	NFP_IPSEC_HASH_SHA512_256,
414 	NFP_IPSEC_HASH_GF128_128,
415 	NFP_IPSEC_HASH_POLY1305_128,
416 };
417 
418 /* Cipher types */
419 enum nfp_ipsec_cipher_type {
420 	NFP_IPSEC_CIPHER_NULL,
421 	NFP_IPSEC_CIPHER_3DES,
422 	NFP_IPSEC_CIPHER_AES128,
423 	NFP_IPSEC_CIPHER_AES192,
424 	NFP_IPSEC_CIPHER_AES256,
425 	NFP_IPSEC_CIPHER_AES128_NULL,
426 	NFP_IPSEC_CIPHER_AES192_NULL,
427 	NFP_IPSEC_CIPHER_AES256_NULL,
428 	NFP_IPSEC_CIPHER_CHACHA20,
429 };
430 
431 /* Don't Fragment types */
432 enum nfp_ipsec_df_type {
433 	NFP_IPSEC_DF_CLEAR,
434 	NFP_IPSEC_DF_SET,
435 	NFP_IPSEC_DF_COPY,
436 };
437 
438 static int
439 nfp_ipsec_cfg_cmd_issue(struct nfp_net_hw *net_hw,
440 		struct nfp_ipsec_msg *msg)
441 {
442 	int ret;
443 	uint32_t i;
444 	uint32_t msg_size;
445 
446 	msg_size = RTE_DIM(msg->raw);
447 	msg->rsp = NFP_IPSEC_CFG_MSG_OK;
448 
449 	for (i = 0; i < msg_size; i++)
450 		nn_cfg_writel(&net_hw->super, NFP_NET_CFG_MBOX_VAL + 4 * i, msg->raw[i]);
451 
452 	ret = nfp_net_mbox_reconfig(net_hw, NFP_NET_CFG_MBOX_CMD_IPSEC);
453 	if (ret < 0) {
454 		PMD_DRV_LOG(ERR, "Failed to IPsec reconfig mbox");
455 		return ret;
456 	}
457 
458 	/*
459 	 * Not all commands and callers make use of response message data. But
460 	 * leave this up to the caller and always read and store the full
461 	 * response. One example where the data is needed is for statistics.
462 	 */
463 	for (i = 0; i < msg_size; i++)
464 		msg->raw[i] = nn_cfg_readl(&net_hw->super, NFP_NET_CFG_MBOX_VAL + 4 * i);
465 
466 	switch (msg->rsp) {
467 	case NFP_IPSEC_CFG_MSG_OK:
468 		ret = 0;
469 		break;
470 	case NFP_IPSEC_CFG_MSG_SA_INVALID_CMD:
471 		ret = -EINVAL;
472 		break;
473 	case NFP_IPSEC_CFG_MSG_SA_VALID:
474 		ret = -EEXIST;
475 		break;
476 	case NFP_IPSEC_CFG_MSG_FAILED:
477 		/* FALLTHROUGH */
478 	case NFP_IPSEC_CFG_MSG_SA_HASH_ADD_FAILED:
479 		/* FALLTHROUGH */
480 	case NFP_IPSEC_CFG_MSG_SA_HASH_DEL_FAILED:
481 		ret = -EIO;
482 		break;
483 	default:
484 		ret = -EDOM;
485 	}
486 
487 	return ret;
488 }
489 
490 /**
491  * Get valid SA index from SA table
492  *
493  * @param data
494  *   SA table pointer
495  * @param sa_idx
496  *   SA table index pointer
497  *
498  * @return
499  *   Negative number on full or repeat, 0 on success
500  *
501  * Note: multiple sockets may create same SA session.
502  */
503 static void
504 nfp_get_sa_entry(struct nfp_net_ipsec_data *data,
505 		int *sa_idx)
506 {
507 	uint32_t i;
508 
509 	for (i = 0; i < NFP_NET_IPSEC_MAX_SA_CNT; i++) {
510 		if (data->sa_entries[i] == NULL) {
511 			*sa_idx = i;
512 			break;
513 		}
514 	}
515 }
516 
517 static void
518 nfp_aesgcm_iv_update(struct ipsec_add_sa *cfg,
519 		uint16_t iv_len,
520 		const char *iv_string)
521 {
522 	int i;
523 	char *save;
524 	char *iv_b;
525 	char *iv_str;
526 	uint8_t *cfg_iv;
527 
528 	iv_str = strdup(iv_string);
529 	if (iv_str == NULL) {
530 		PMD_DRV_LOG(ERR, "Failed to strdup iv_string");
531 		return;
532 	}
533 
534 	cfg_iv = (uint8_t *)cfg->aesgcm_fields.iv;
535 
536 	for (i = 0; i < iv_len; i++) {
537 		iv_b = strtok_r(i ? NULL : iv_str, ",", &save);
538 		if (iv_b == NULL)
539 			break;
540 
541 		cfg_iv[i] = strtoul(iv_b, NULL, 0);
542 	}
543 
544 	*(uint32_t *)cfg_iv = rte_be_to_cpu_32(*(uint32_t *)cfg_iv);
545 	*(uint32_t *)&cfg_iv[4] = rte_be_to_cpu_32(*(uint32_t *)&cfg_iv[4]);
546 
547 	free(iv_str);
548 }
549 
550 static int
551 set_aes_keylen(uint32_t key_length,
552 		struct ipsec_add_sa *cfg)
553 {
554 	switch (key_length << 3) {
555 	case 128:
556 		cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_AES128;
557 		break;
558 	case 192:
559 		cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_AES192;
560 		break;
561 	case 256:
562 		cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_AES256;
563 		break;
564 	default:
565 		PMD_DRV_LOG(ERR, "AES cipher key length is illegal!");
566 		return -EINVAL;
567 	}
568 
569 	return 0;
570 }
571 
572 /* Map rte_security_session_conf aead algo to NFP aead algo */
573 static int
574 nfp_aead_map(struct rte_eth_dev *eth_dev,
575 		struct rte_crypto_aead_xform *aead,
576 		uint32_t key_length,
577 		struct ipsec_add_sa *cfg)
578 {
579 	int ret;
580 	uint32_t i;
581 	uint32_t index;
582 	uint16_t iv_len;
583 	uint32_t offset;
584 	uint32_t device_id;
585 	const char *iv_str;
586 	const uint32_t *key;
587 	struct nfp_net_hw *net_hw;
588 
589 	net_hw = eth_dev->data->dev_private;
590 	device_id = net_hw->device_id;
591 	offset = 0;
592 
593 	switch (aead->algo) {
594 	case RTE_CRYPTO_AEAD_AES_GCM:
595 		if (aead->digest_length != 16) {
596 			PMD_DRV_LOG(ERR, "ICV must be 128bit with RTE_CRYPTO_AEAD_AES_GCM!");
597 			return -EINVAL;
598 		}
599 
600 		cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CTR;
601 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_GF128_128;
602 
603 		ret = set_aes_keylen(key_length, cfg);
604 		if (ret < 0) {
605 			PMD_DRV_LOG(ERR, "Failed to set AES_GCM key length!");
606 			return -EINVAL;
607 		}
608 
609 		break;
610 	case RTE_CRYPTO_AEAD_CHACHA20_POLY1305:
611 		if (device_id != PCI_DEVICE_ID_NFP3800_PF_NIC) {
612 			PMD_DRV_LOG(ERR, "Unsupported aead CHACHA20_POLY1305 algorithm!");
613 			return -EINVAL;
614 		}
615 
616 		if (aead->digest_length != 16) {
617 			PMD_DRV_LOG(ERR, "ICV must be 128bit with RTE_CRYPTO_AEAD_CHACHA20_POLY1305");
618 			return -EINVAL;
619 		}
620 
621 		/* Aead->alg_key_len includes 32-bit salt */
622 		if (key_length != 32) {
623 			PMD_DRV_LOG(ERR, "Unsupported CHACHA20 key length");
624 			return -EINVAL;
625 		}
626 
627 		/* The CHACHA20's mode is not configured */
628 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_POLY1305_128;
629 		cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_CHACHA20;
630 		break;
631 	default:
632 		PMD_DRV_LOG(ERR, "Unsupported aead algorithm!");
633 		return -EINVAL;
634 	}
635 
636 	key = (const uint32_t *)(aead->key.data);
637 
638 	/*
639 	 * The CHACHA20's key order needs to be adjusted based on hardware design.
640 	 * Unadjusted order: {K0, K1, K2, K3, K4, K5, K6, K7}
641 	 * Adjusted order: {K4, K5, K6, K7, K0, K1, K2, K3}
642 	 */
643 	if (aead->algo == RTE_CRYPTO_AEAD_CHACHA20_POLY1305)
644 		offset = key_length / sizeof(cfg->cipher_key[0]) << 1;
645 
646 	for (i = 0; i < key_length / sizeof(cfg->cipher_key[0]); i++) {
647 		index = (i + offset) % (key_length / sizeof(cfg->cipher_key[0]));
648 		cfg->cipher_key[index] = rte_cpu_to_be_32(*key++);
649 	}
650 
651 	/*
652 	 * The iv of the FW is equal to ESN by default. Reading the
653 	 * iv of the configuration information is not supported.
654 	 */
655 	iv_str = getenv("ETH_SEC_IV_OVR");
656 	if (iv_str != NULL) {
657 		iv_len = aead->iv.length;
658 		nfp_aesgcm_iv_update(cfg, iv_len, iv_str);
659 	}
660 
661 	return 0;
662 }
663 
664 /* Map rte_security_session_conf cipher algo to NFP cipher algo */
665 static int
666 nfp_cipher_map(struct rte_eth_dev *eth_dev,
667 		struct rte_crypto_cipher_xform *cipher,
668 		uint32_t key_length,
669 		struct ipsec_add_sa *cfg)
670 {
671 	int ret;
672 	uint32_t i;
673 	uint32_t device_id;
674 	const uint32_t *key;
675 	struct nfp_net_hw *net_hw;
676 
677 	net_hw = eth_dev->data->dev_private;
678 	device_id = net_hw->device_id;
679 
680 	switch (cipher->algo) {
681 	case RTE_CRYPTO_CIPHER_NULL:
682 		cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CBC;
683 		cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_NULL;
684 		break;
685 	case RTE_CRYPTO_CIPHER_3DES_CBC:
686 		if (device_id == PCI_DEVICE_ID_NFP3800_PF_NIC) {
687 			PMD_DRV_LOG(ERR, "Unsupported 3DESCBC encryption algorithm!");
688 			return -EINVAL;
689 		}
690 
691 		cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CBC;
692 		cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_3DES;
693 		break;
694 	case RTE_CRYPTO_CIPHER_AES_CBC:
695 		cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CBC;
696 		ret = set_aes_keylen(key_length, cfg);
697 		if (ret < 0) {
698 			PMD_DRV_LOG(ERR, "Failed to set cipher key length!");
699 			return -EINVAL;
700 		}
701 
702 		break;
703 	default:
704 		PMD_DRV_LOG(ERR, "Unsupported cipher alg!");
705 		return -EINVAL;
706 	}
707 
708 	key = (const uint32_t  *)(cipher->key.data);
709 	if (key_length > sizeof(cfg->cipher_key)) {
710 		PMD_DRV_LOG(ERR, "Insufficient space for offloaded key");
711 		return -EINVAL;
712 	}
713 
714 	for (i = 0; i < key_length / sizeof(cfg->cipher_key[0]); i++)
715 		cfg->cipher_key[i] = rte_cpu_to_be_32(*key++);
716 
717 	return 0;
718 }
719 
720 static void
721 set_md5hmac(struct ipsec_add_sa *cfg,
722 		uint32_t *digest_length)
723 {
724 	switch (*digest_length) {
725 	case 96:
726 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_MD5_96;
727 		break;
728 	case 128:
729 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_MD5_128;
730 		break;
731 	default:
732 		*digest_length = 0;
733 	}
734 }
735 
736 static void
737 set_sha1hmac(struct ipsec_add_sa *cfg,
738 		uint32_t *digest_length)
739 {
740 	switch (*digest_length) {
741 	case 96:
742 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA1_96;
743 		break;
744 	case 80:
745 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA1_80;
746 		break;
747 	default:
748 		*digest_length = 0;
749 	}
750 }
751 
752 static void
753 set_sha2_256hmac(struct ipsec_add_sa *cfg,
754 		uint32_t *digest_length)
755 {
756 	switch (*digest_length) {
757 	case 96:
758 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA256_96;
759 		break;
760 	case 128:
761 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA256_128;
762 		break;
763 	default:
764 		*digest_length = 0;
765 	}
766 }
767 
768 static void
769 set_sha2_384hmac(struct ipsec_add_sa *cfg,
770 		uint32_t *digest_length)
771 {
772 	switch (*digest_length) {
773 	case 96:
774 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA384_96;
775 		break;
776 	case 192:
777 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA384_192;
778 		break;
779 	default:
780 		*digest_length = 0;
781 	}
782 }
783 
784 static void
785 set_sha2_512hmac(struct ipsec_add_sa *cfg,
786 		uint32_t *digest_length)
787 {
788 	switch (*digest_length) {
789 	case 96:
790 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA512_96;
791 		break;
792 	case 256:
793 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA512_256;
794 		break;
795 	default:
796 		*digest_length = 0;
797 	}
798 }
799 
800 /* Map rte_security_session_conf auth algo to NFP auth algo */
801 static int
802 nfp_auth_map(struct rte_eth_dev *eth_dev,
803 		struct rte_crypto_auth_xform *auth,
804 		uint32_t digest_length,
805 		struct ipsec_add_sa *cfg)
806 {
807 	uint32_t i;
808 	uint8_t key_length;
809 	uint32_t device_id;
810 	const uint32_t *key;
811 	struct nfp_net_hw *net_hw;
812 
813 	if (digest_length == 0) {
814 		PMD_DRV_LOG(ERR, "Auth digest length is illegal!");
815 		return -EINVAL;
816 	}
817 
818 	net_hw = eth_dev->data->dev_private;
819 	device_id = net_hw->device_id;
820 	digest_length = digest_length << 3;
821 
822 	switch (auth->algo) {
823 	case RTE_CRYPTO_AUTH_NULL:
824 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_NONE;
825 		digest_length = 1;
826 		break;
827 	case RTE_CRYPTO_AUTH_MD5_HMAC:
828 		if (device_id == PCI_DEVICE_ID_NFP3800_PF_NIC) {
829 			PMD_DRV_LOG(ERR, "Unsupported MD5HMAC authentication algorithm!");
830 			return -EINVAL;
831 		}
832 
833 		set_md5hmac(cfg, &digest_length);
834 		break;
835 	case RTE_CRYPTO_AUTH_SHA1_HMAC:
836 		set_sha1hmac(cfg, &digest_length);
837 		break;
838 	case RTE_CRYPTO_AUTH_SHA256_HMAC:
839 		set_sha2_256hmac(cfg, &digest_length);
840 		break;
841 	case RTE_CRYPTO_AUTH_SHA384_HMAC:
842 		set_sha2_384hmac(cfg, &digest_length);
843 		break;
844 	case RTE_CRYPTO_AUTH_SHA512_HMAC:
845 		set_sha2_512hmac(cfg, &digest_length);
846 		break;
847 	default:
848 		PMD_DRV_LOG(ERR, "Unsupported auth alg!");
849 		return -EINVAL;
850 	}
851 
852 	if (digest_length == 0) {
853 		PMD_DRV_LOG(ERR, "Unsupported authentication algorithm digest length");
854 		return -EINVAL;
855 	}
856 
857 	key = (const uint32_t *)(auth->key.data);
858 	key_length = auth->key.length;
859 	if (key_length > sizeof(cfg->auth_key)) {
860 		PMD_DRV_LOG(ERR, "Insufficient space for offloaded auth key!");
861 		return -EINVAL;
862 	}
863 
864 	for (i = 0; i < key_length / sizeof(cfg->auth_key[0]); i++)
865 		cfg->auth_key[i] = rte_cpu_to_be_32(*key++);
866 
867 	return 0;
868 }
869 
870 static int
871 nfp_crypto_msg_build(struct rte_eth_dev *eth_dev,
872 		struct rte_security_session_conf *conf,
873 		struct nfp_ipsec_msg *msg)
874 {
875 	int ret;
876 	struct ipsec_add_sa *cfg;
877 	struct rte_crypto_sym_xform *cur;
878 	struct rte_crypto_sym_xform *next;
879 	enum rte_security_ipsec_sa_direction direction;
880 
881 	cur = conf->crypto_xform;
882 	if (cur == NULL) {
883 		PMD_DRV_LOG(ERR, "Unsupported crypto_xform is NULL!");
884 		return -EINVAL;
885 	}
886 
887 	next = cur->next;
888 	direction = conf->ipsec.direction;
889 	cfg = &msg->cfg_add_sa;
890 
891 	switch (cur->type) {
892 	case RTE_CRYPTO_SYM_XFORM_AEAD:
893 		/* Aead transforms can be used for either inbound/outbound IPsec SAs */
894 		if (next != NULL) {
895 			PMD_DRV_LOG(ERR, "Next crypto_xform type should be NULL!");
896 			return -EINVAL;
897 		}
898 
899 		ret = nfp_aead_map(eth_dev, &cur->aead, cur->aead.key.length, cfg);
900 		if (ret < 0) {
901 			PMD_DRV_LOG(ERR, "Failed to map aead alg!");
902 			return ret;
903 		}
904 
905 		cfg->aesgcm_fields.salt = rte_cpu_to_be_32(conf->ipsec.salt);
906 		break;
907 	case RTE_CRYPTO_SYM_XFORM_AUTH:
908 		/* Only support Auth + Cipher for inbound */
909 		if (direction != RTE_SECURITY_IPSEC_SA_DIR_INGRESS) {
910 			PMD_DRV_LOG(ERR, "Direction should be INGRESS, but it is not!");
911 			return -EINVAL;
912 		}
913 
914 		if (next == NULL || next->type != RTE_CRYPTO_SYM_XFORM_CIPHER) {
915 			PMD_DRV_LOG(ERR, "Next crypto_xfrm should be cipher, but it is not!");
916 			return -EINVAL;
917 		}
918 
919 		ret = nfp_auth_map(eth_dev, &cur->auth, cur->auth.digest_length, cfg);
920 		if (ret < 0) {
921 			PMD_DRV_LOG(ERR, "Failed to map auth alg!");
922 			return ret;
923 		}
924 
925 		ret = nfp_cipher_map(eth_dev, &next->cipher, next->cipher.key.length, cfg);
926 		if (ret < 0) {
927 			PMD_DRV_LOG(ERR, "Failed to map cipher alg!");
928 			return ret;
929 		}
930 
931 		break;
932 	case RTE_CRYPTO_SYM_XFORM_CIPHER:
933 		/* Only support Cipher + Auth for outbound */
934 		if (direction != RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
935 			PMD_DRV_LOG(ERR, "Direction should be EGRESS, but it is not!");
936 			return -EINVAL;
937 		}
938 
939 		if (next == NULL || next->type != RTE_CRYPTO_SYM_XFORM_AUTH) {
940 			PMD_DRV_LOG(ERR, "Next crypto_xfrm should be auth, but it is not!");
941 			return -EINVAL;
942 		}
943 
944 		ret = nfp_cipher_map(eth_dev, &cur->cipher, cur->cipher.key.length, cfg);
945 		if (ret < 0) {
946 			PMD_DRV_LOG(ERR, "Failed to map cipher alg!");
947 			return ret;
948 		}
949 
950 		ret = nfp_auth_map(eth_dev, &next->auth, next->auth.digest_length, cfg);
951 		if (ret < 0) {
952 			PMD_DRV_LOG(ERR, "Failed to map auth alg!");
953 			return ret;
954 		}
955 
956 		break;
957 	default:
958 		PMD_DRV_LOG(ERR, "Unsupported crypto_xform type!");
959 		return -EINVAL;
960 	}
961 
962 	return 0;
963 }
964 
965 static int
966 nfp_ipsec_msg_build(struct rte_eth_dev *eth_dev,
967 		struct rte_security_session_conf *conf,
968 		struct nfp_ipsec_msg *msg)
969 {
970 	int ret;
971 	struct ipsec_add_sa *cfg;
972 	enum rte_security_ipsec_tunnel_type type;
973 
974 	cfg = &msg->cfg_add_sa;
975 	cfg->spi = conf->ipsec.spi;
976 	cfg->pmtu_limit = 0xffff;
977 
978 	/*
979 	 * UDP encapsulation
980 	 *
981 	 * 1: Do UDP encapsulation/decapsulation
982 	 * 0: No UDP encapsulation
983 	 */
984 	if (conf->ipsec.options.udp_encap == 1) {
985 		cfg->udp_enable = 1;
986 		cfg->natt_dst_port = NFP_UDP_ESP_PORT;
987 		cfg->natt_src_port = NFP_UDP_ESP_PORT;
988 	}
989 
990 	if (conf->ipsec.options.copy_df == 1)
991 		cfg->df_ctrl = NFP_IPSEC_DF_COPY;
992 	else if (conf->ipsec.tunnel.ipv4.df != 0)
993 		cfg->df_ctrl = NFP_IPSEC_DF_SET;
994 	else
995 		cfg->df_ctrl = NFP_IPSEC_DF_CLEAR;
996 
997 	switch (conf->action_type) {
998 	case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO:
999 		cfg->ctrl_word.encap_dsbl = 1;
1000 		break;
1001 	case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL:
1002 		cfg->ctrl_word.encap_dsbl = 0;
1003 		break;
1004 	default:
1005 		PMD_DRV_LOG(ERR, "Unsupported IPsec action for offload, action: %d",
1006 				conf->action_type);
1007 		return -EINVAL;
1008 	}
1009 
1010 	switch (conf->ipsec.proto) {
1011 	case RTE_SECURITY_IPSEC_SA_PROTO_ESP:
1012 		cfg->ctrl_word.proto = NFP_IPSEC_PROTOCOL_ESP;
1013 		break;
1014 	case RTE_SECURITY_IPSEC_SA_PROTO_AH:
1015 		cfg->ctrl_word.proto = NFP_IPSEC_PROTOCOL_AH;
1016 		break;
1017 	default:
1018 		PMD_DRV_LOG(ERR, "Unsupported IPsec protocol for offload, protocol: %d",
1019 				conf->ipsec.proto);
1020 		return -EINVAL;
1021 	}
1022 
1023 	switch (conf->ipsec.mode) {
1024 	case RTE_SECURITY_IPSEC_SA_MODE_TUNNEL:
1025 		type = conf->ipsec.tunnel.type;
1026 		cfg->ctrl_word.mode = NFP_IPSEC_MODE_TUNNEL;
1027 		if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV4) {
1028 			cfg->src_ip.v4 = conf->ipsec.tunnel.ipv4.src_ip;
1029 			cfg->dst_ip.v4 = conf->ipsec.tunnel.ipv4.dst_ip;
1030 			cfg->ipv6 = 0;
1031 		} else if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV6) {
1032 			cfg->src_ip.v6 = conf->ipsec.tunnel.ipv6.src_addr;
1033 			cfg->dst_ip.v6 = conf->ipsec.tunnel.ipv6.dst_addr;
1034 			cfg->ipv6 = 1;
1035 		} else {
1036 			PMD_DRV_LOG(ERR, "Unsupported address family!");
1037 			return -EINVAL;
1038 		}
1039 
1040 		break;
1041 	case RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT:
1042 		type = conf->ipsec.tunnel.type;
1043 		cfg->ctrl_word.mode = NFP_IPSEC_MODE_TRANSPORT;
1044 		if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV4) {
1045 			memset(&cfg->src_ip, 0, sizeof(cfg->src_ip));
1046 			cfg->ipv6 = 0;
1047 		} else if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV6) {
1048 			memset(&cfg->src_ip, 0, sizeof(cfg->src_ip));
1049 			cfg->ipv6 = 1;
1050 		} else {
1051 			PMD_DRV_LOG(ERR, "Unsupported address family!");
1052 			return -EINVAL;
1053 		}
1054 
1055 		break;
1056 	default:
1057 		PMD_DRV_LOG(ERR, "Unsupported IPsec mode for offload, mode: %d",
1058 				conf->ipsec.mode);
1059 		return -EINVAL;
1060 	}
1061 
1062 	ret = nfp_crypto_msg_build(eth_dev, conf, msg);
1063 	if (ret < 0) {
1064 		PMD_DRV_LOG(ERR, "Failed to build auth/crypto/aead msg!");
1065 		return ret;
1066 	}
1067 
1068 	return 0;
1069 }
1070 
1071 static int
1072 nfp_crypto_create_session(void *device,
1073 		struct rte_security_session_conf *conf,
1074 		struct rte_security_session *session)
1075 {
1076 	int ret;
1077 	int sa_idx;
1078 	struct nfp_net_hw *net_hw;
1079 	struct nfp_ipsec_msg msg;
1080 	struct rte_eth_dev *eth_dev;
1081 	struct nfp_ipsec_session *priv_session;
1082 
1083 	/* Only support IPsec at present */
1084 	if (conf->protocol != RTE_SECURITY_PROTOCOL_IPSEC) {
1085 		PMD_DRV_LOG(ERR, "Unsupported non-IPsec offload!");
1086 		return -EINVAL;
1087 	}
1088 
1089 	sa_idx = -1;
1090 	eth_dev = device;
1091 	priv_session = SECURITY_GET_SESS_PRIV(session);
1092 	net_hw = eth_dev->data->dev_private;
1093 
1094 	if (net_hw->ipsec_data->sa_free_cnt == 0) {
1095 		PMD_DRV_LOG(ERR, "No space in SA table, spi: %d", conf->ipsec.spi);
1096 		return -EINVAL;
1097 	}
1098 
1099 	nfp_get_sa_entry(net_hw->ipsec_data, &sa_idx);
1100 
1101 	if (sa_idx < 0) {
1102 		PMD_DRV_LOG(ERR, "Failed to get SA entry!");
1103 		return -EINVAL;
1104 	}
1105 
1106 	memset(&msg, 0, sizeof(msg));
1107 	ret = nfp_ipsec_msg_build(eth_dev, conf, &msg);
1108 	if (ret < 0) {
1109 		PMD_DRV_LOG(ERR, "Failed to build IPsec msg!");
1110 		return -EINVAL;
1111 	}
1112 
1113 	msg.cmd = NFP_IPSEC_CFG_MSG_ADD_SA;
1114 	msg.sa_idx = sa_idx;
1115 	ret = nfp_ipsec_cfg_cmd_issue(net_hw, &msg);
1116 	if (ret < 0) {
1117 		PMD_DRV_LOG(ERR, "Failed to add SA to nic");
1118 		return -EINVAL;
1119 	}
1120 
1121 	priv_session->action = conf->action_type;
1122 	priv_session->ipsec = conf->ipsec;
1123 	priv_session->msg = msg.cfg_add_sa;
1124 	priv_session->sa_index = sa_idx;
1125 	priv_session->dev = eth_dev;
1126 	priv_session->user_data = conf->userdata;
1127 
1128 	net_hw->ipsec_data->sa_free_cnt--;
1129 	net_hw->ipsec_data->sa_entries[sa_idx] = priv_session;
1130 
1131 	return 0;
1132 }
1133 
1134 static int
1135 nfp_crypto_update_session(void *device __rte_unused,
1136 		struct rte_security_session *session,
1137 		struct rte_security_session_conf *conf)
1138 {
1139 	struct nfp_ipsec_session *priv_session;
1140 
1141 	priv_session = SECURITY_GET_SESS_PRIV(session);
1142 	if (priv_session == NULL)
1143 		return -EINVAL;
1144 
1145 	/* Update IPsec ESN value */
1146 	if (priv_session->msg.ctrl_word.ext_seq != 0 && conf->ipsec.options.esn != 0) {
1147 		/*
1148 		 * Store in nfp_ipsec_session for outbound SA for use
1149 		 * in nfp_security_set_pkt_metadata() function.
1150 		 */
1151 		priv_session->ipsec.esn.hi = conf->ipsec.esn.hi;
1152 		priv_session->ipsec.esn.low = conf->ipsec.esn.low;
1153 	}
1154 
1155 	return 0;
1156 }
1157 
1158 static int
1159 nfp_security_set_pkt_metadata(void *device,
1160 		struct rte_security_session *session,
1161 		struct rte_mbuf *m,
1162 		void *params)
1163 {
1164 	int offset;
1165 	uint64_t *sqn;
1166 	struct nfp_net_hw *net_hw;
1167 	struct rte_eth_dev *eth_dev;
1168 	struct nfp_ipsec_session *priv_session;
1169 
1170 	sqn = params;
1171 	eth_dev = device;
1172 	priv_session = SECURITY_GET_SESS_PRIV(session);
1173 	net_hw = eth_dev->data->dev_private;
1174 
1175 	if (priv_session->ipsec.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
1176 		struct nfp_tx_ipsec_desc_msg *desc_md;
1177 
1178 		offset = net_hw->ipsec_data->pkt_dynfield_offset;
1179 		desc_md = RTE_MBUF_DYNFIELD(m, offset, struct nfp_tx_ipsec_desc_msg *);
1180 
1181 		if (priv_session->msg.ctrl_word.ext_seq != 0 && sqn != NULL) {
1182 			desc_md->esn.low = rte_cpu_to_be_32(*sqn);
1183 			desc_md->esn.hi = rte_cpu_to_be_32(*sqn >> 32);
1184 		} else if (priv_session->msg.ctrl_word.ext_seq != 0) {
1185 			desc_md->esn.low = rte_cpu_to_be_32(priv_session->ipsec.esn.low);
1186 			desc_md->esn.hi = rte_cpu_to_be_32(priv_session->ipsec.esn.hi);
1187 		} else {
1188 			desc_md->esn.low = rte_cpu_to_be_32(priv_session->ipsec.esn.value);
1189 			desc_md->esn.hi = 0;
1190 		}
1191 
1192 		desc_md->enc = 1;
1193 		desc_md->sa_idx = rte_cpu_to_be_32(priv_session->sa_index);
1194 	}
1195 
1196 	return 0;
1197 }
1198 
1199 /**
1200  * Get discards packet statistics for each SA
1201  *
1202  * The sa_discard_stats contains the statistics of discards packets
1203  * of an SA. This function calculates the sum total of discarded packets.
1204  *
1205  * @param errors
1206  *   The value is SA discards packet sum total
1207  * @param sa_discard_stats
1208  *   The struct is SA discards packet Statistics
1209  */
1210 static void
1211 nfp_get_errorstats(uint64_t *errors,
1212 		struct ipsec_discard_stats *sa_discard_stats)
1213 {
1214 	uint32_t i;
1215 	uint32_t len;
1216 	uint32_t *perror;
1217 
1218 	perror = &sa_discard_stats->discards_auth;
1219 	len = sizeof(struct ipsec_discard_stats) / sizeof(uint32_t);
1220 
1221 	for (i = 0; i < len; i++)
1222 		*errors += *perror++;
1223 
1224 	*errors -= sa_discard_stats->ipv4_id_counter;
1225 }
1226 
1227 static int
1228 nfp_security_session_get_stats(void *device,
1229 		struct rte_security_session *session,
1230 		struct rte_security_stats *stats)
1231 {
1232 	int ret;
1233 	struct nfp_net_hw *net_hw;
1234 	struct nfp_ipsec_msg msg;
1235 	struct rte_eth_dev *eth_dev;
1236 	struct ipsec_get_sa_stats *cfg_s;
1237 	struct rte_security_ipsec_stats *ips_s;
1238 	struct nfp_ipsec_session *priv_session;
1239 	enum rte_security_ipsec_sa_direction direction;
1240 
1241 	eth_dev = device;
1242 	priv_session = SECURITY_GET_SESS_PRIV(session);
1243 	memset(&msg, 0, sizeof(msg));
1244 	msg.cmd = NFP_IPSEC_CFG_MSG_GET_SA_STATS;
1245 	msg.sa_idx = priv_session->sa_index;
1246 	net_hw = eth_dev->data->dev_private;
1247 
1248 	ret = nfp_ipsec_cfg_cmd_issue(net_hw, &msg);
1249 	if (ret < 0) {
1250 		PMD_DRV_LOG(ERR, "Failed to get SA stats");
1251 		return ret;
1252 	}
1253 
1254 	cfg_s = &msg.cfg_get_stats;
1255 	direction = priv_session->ipsec.direction;
1256 	memset(stats, 0, sizeof(struct rte_security_stats)); /* Start with zeros */
1257 	stats->protocol = RTE_SECURITY_PROTOCOL_IPSEC;
1258 	ips_s = &stats->ipsec;
1259 
1260 	/* Only display SA if any counters are non-zero */
1261 	if (cfg_s->lifetime_byte_count != 0 || cfg_s->pkt_count != 0) {
1262 		if (direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) {
1263 			ips_s->ipackets = cfg_s->pkt_count;
1264 			ips_s->ibytes = cfg_s->lifetime_byte_count;
1265 			nfp_get_errorstats(&ips_s->ierrors, &cfg_s->sa_discard_stats);
1266 		} else {
1267 			ips_s->opackets = cfg_s->pkt_count;
1268 			ips_s->obytes = cfg_s->lifetime_byte_count;
1269 			nfp_get_errorstats(&ips_s->oerrors, &cfg_s->sa_discard_stats);
1270 		}
1271 	}
1272 
1273 	return 0;
1274 }
1275 
1276 static const struct rte_security_capability *
1277 nfp_crypto_capabilities_get(void *device __rte_unused)
1278 {
1279 	return nfp_security_caps;
1280 }
1281 
1282 static uint32_t
1283 nfp_security_session_get_size(void *device __rte_unused)
1284 {
1285 	return sizeof(struct nfp_ipsec_session);
1286 }
1287 
1288 static int
1289 nfp_crypto_remove_sa(struct rte_eth_dev *eth_dev,
1290 		struct nfp_ipsec_session *priv_session)
1291 {
1292 	int ret;
1293 	uint32_t sa_index;
1294 	struct nfp_net_hw *net_hw;
1295 	struct nfp_ipsec_msg cfg;
1296 
1297 	sa_index = priv_session->sa_index;
1298 	net_hw = eth_dev->data->dev_private;
1299 
1300 	cfg.cmd = NFP_IPSEC_CFG_MSG_INV_SA;
1301 	cfg.sa_idx = sa_index;
1302 	ret = nfp_ipsec_cfg_cmd_issue(net_hw, &cfg);
1303 	if (ret < 0) {
1304 		PMD_DRV_LOG(ERR, "Failed to remove SA!");
1305 		return -EINVAL;
1306 	}
1307 
1308 	net_hw->ipsec_data->sa_free_cnt++;
1309 	net_hw->ipsec_data->sa_entries[sa_index] = NULL;
1310 
1311 	return 0;
1312 }
1313 
1314 static int
1315 nfp_crypto_remove_session(void *device,
1316 		struct rte_security_session *session)
1317 {
1318 	int ret;
1319 	struct rte_eth_dev *eth_dev;
1320 	struct nfp_ipsec_session *priv_session;
1321 
1322 	eth_dev = device;
1323 	priv_session = SECURITY_GET_SESS_PRIV(session);
1324 	if (eth_dev != priv_session->dev) {
1325 		PMD_DRV_LOG(ERR, "Session not bound to this device");
1326 		return -ENODEV;
1327 	}
1328 
1329 	ret = nfp_crypto_remove_sa(eth_dev, priv_session);
1330 	if (ret < 0) {
1331 		PMD_DRV_LOG(ERR, "Failed to remove session");
1332 		return -EFAULT;
1333 	}
1334 
1335 	memset(priv_session, 0, sizeof(struct nfp_ipsec_session));
1336 
1337 	return 0;
1338 }
1339 
1340 static const struct rte_security_ops nfp_security_ops = {
1341 	.session_create = nfp_crypto_create_session,
1342 	.session_update = nfp_crypto_update_session,
1343 	.session_get_size = nfp_security_session_get_size,
1344 	.session_stats_get = nfp_security_session_get_stats,
1345 	.session_destroy = nfp_crypto_remove_session,
1346 	.set_pkt_metadata = nfp_security_set_pkt_metadata,
1347 	.capabilities_get = nfp_crypto_capabilities_get,
1348 };
1349 
1350 static int
1351 nfp_ipsec_ctx_create(struct rte_eth_dev *dev,
1352 		struct nfp_net_ipsec_data *data)
1353 {
1354 	struct rte_security_ctx *ctx;
1355 	static const struct rte_mbuf_dynfield pkt_md_dynfield = {
1356 		.name = "nfp_ipsec_crypto_pkt_metadata",
1357 		.size = sizeof(struct nfp_tx_ipsec_desc_msg),
1358 		.align = alignof(struct nfp_tx_ipsec_desc_msg),
1359 	};
1360 
1361 	ctx = rte_zmalloc("security_ctx",
1362 			sizeof(struct rte_security_ctx), 0);
1363 	if (ctx == NULL) {
1364 		PMD_INIT_LOG(ERR, "Failed to malloc security_ctx");
1365 		return -ENOMEM;
1366 	}
1367 
1368 	ctx->device = dev;
1369 	ctx->ops = &nfp_security_ops;
1370 	ctx->sess_cnt = 0;
1371 	dev->security_ctx = ctx;
1372 
1373 	data->pkt_dynfield_offset = rte_mbuf_dynfield_register(&pkt_md_dynfield);
1374 	if (data->pkt_dynfield_offset < 0) {
1375 		PMD_INIT_LOG(ERR, "Failed to register mbuf esn_dynfield");
1376 		return -ENOMEM;
1377 	}
1378 
1379 	return 0;
1380 }
1381 
1382 int
1383 nfp_ipsec_init(struct rte_eth_dev *dev)
1384 {
1385 	int ret;
1386 	uint32_t cap_extend;
1387 	struct nfp_net_hw *net_hw;
1388 	struct nfp_net_ipsec_data *data;
1389 
1390 	net_hw = dev->data->dev_private;
1391 
1392 	cap_extend = net_hw->super.cap_ext;
1393 	if ((cap_extend & NFP_NET_CFG_CTRL_IPSEC) == 0) {
1394 		PMD_INIT_LOG(INFO, "Unsupported IPsec extend capability");
1395 		return 0;
1396 	}
1397 
1398 	data = rte_zmalloc("ipsec_data", sizeof(struct nfp_net_ipsec_data), 0);
1399 	if (data == NULL) {
1400 		PMD_INIT_LOG(ERR, "Failed to malloc ipsec_data");
1401 		return -ENOMEM;
1402 	}
1403 
1404 	data->pkt_dynfield_offset = -1;
1405 	data->sa_free_cnt = NFP_NET_IPSEC_MAX_SA_CNT;
1406 	net_hw->ipsec_data = data;
1407 
1408 	ret = nfp_ipsec_ctx_create(dev, data);
1409 	if (ret != 0) {
1410 		PMD_INIT_LOG(ERR, "Failed to create IPsec ctx");
1411 		goto ipsec_cleanup;
1412 	}
1413 
1414 	return 0;
1415 
1416 ipsec_cleanup:
1417 	nfp_ipsec_uninit(dev);
1418 
1419 	return ret;
1420 }
1421 
1422 static void
1423 nfp_ipsec_ctx_destroy(struct rte_eth_dev *dev)
1424 {
1425 	rte_free(dev->security_ctx);
1426 }
1427 
1428 void
1429 nfp_ipsec_uninit(struct rte_eth_dev *dev)
1430 {
1431 	uint16_t i;
1432 	uint32_t cap_extend;
1433 	struct nfp_net_hw *net_hw;
1434 	struct nfp_ipsec_session *priv_session;
1435 
1436 	net_hw = dev->data->dev_private;
1437 
1438 	cap_extend = net_hw->super.cap_ext;
1439 	if ((cap_extend & NFP_NET_CFG_CTRL_IPSEC) == 0) {
1440 		PMD_INIT_LOG(INFO, "Unsupported IPsec extend capability");
1441 		return;
1442 	}
1443 
1444 	nfp_ipsec_ctx_destroy(dev);
1445 
1446 	if (net_hw->ipsec_data == NULL) {
1447 		PMD_INIT_LOG(INFO, "IPsec data is NULL!");
1448 		return;
1449 	}
1450 
1451 	for (i = 0; i < NFP_NET_IPSEC_MAX_SA_CNT; i++) {
1452 		priv_session = net_hw->ipsec_data->sa_entries[i];
1453 		if (priv_session != NULL)
1454 			memset(priv_session, 0, sizeof(struct nfp_ipsec_session));
1455 	}
1456 
1457 	rte_free(net_hw->ipsec_data);
1458 }
1459 
1460