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