xref: /dpdk/drivers/net/nfp/nfp_ipsec.c (revision 08966fe7f79fdaa5019b7559eebe84a1e3787b89)
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 	cfg_iv = (uint8_t *)cfg->aesgcm_fields.iv;
530 
531 	for (i = 0; i < iv_len; i++) {
532 		iv_b = strtok_r(i ? NULL : iv_str, ",", &save);
533 		if (iv_b == NULL)
534 			break;
535 
536 		cfg_iv[i] = strtoul(iv_b, NULL, 0);
537 	}
538 
539 	*(uint32_t *)cfg_iv = rte_be_to_cpu_32(*(uint32_t *)cfg_iv);
540 	*(uint32_t *)&cfg_iv[4] = rte_be_to_cpu_32(*(uint32_t *)&cfg_iv[4]);
541 
542 	free(iv_str);
543 }
544 
545 static int
546 set_aes_keylen(uint32_t key_length,
547 		struct ipsec_add_sa *cfg)
548 {
549 	switch (key_length << 3) {
550 	case 128:
551 		cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_AES128;
552 		break;
553 	case 192:
554 		cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_AES192;
555 		break;
556 	case 256:
557 		cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_AES256;
558 		break;
559 	default:
560 		PMD_DRV_LOG(ERR, "AES cipher key length is illegal!");
561 		return -EINVAL;
562 	}
563 
564 	return 0;
565 }
566 
567 /* Map rte_security_session_conf aead algo to NFP aead algo */
568 static int
569 nfp_aead_map(struct rte_eth_dev *eth_dev,
570 		struct rte_crypto_aead_xform *aead,
571 		uint32_t key_length,
572 		struct ipsec_add_sa *cfg)
573 {
574 	int ret;
575 	uint32_t i;
576 	uint32_t index;
577 	uint16_t iv_len;
578 	uint32_t offset;
579 	uint32_t device_id;
580 	const char *iv_str;
581 	const uint32_t *key;
582 	struct nfp_net_hw *net_hw;
583 
584 	net_hw = eth_dev->data->dev_private;
585 	device_id = net_hw->device_id;
586 	offset = 0;
587 
588 	switch (aead->algo) {
589 	case RTE_CRYPTO_AEAD_AES_GCM:
590 		if (aead->digest_length != 16) {
591 			PMD_DRV_LOG(ERR, "ICV must be 128bit with RTE_CRYPTO_AEAD_AES_GCM!");
592 			return -EINVAL;
593 		}
594 
595 		cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CTR;
596 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_GF128_128;
597 
598 		ret = set_aes_keylen(key_length, cfg);
599 		if (ret < 0) {
600 			PMD_DRV_LOG(ERR, "Failed to set AES_GCM key length!");
601 			return -EINVAL;
602 		}
603 
604 		break;
605 	case RTE_CRYPTO_AEAD_CHACHA20_POLY1305:
606 		if (device_id != PCI_DEVICE_ID_NFP3800_PF_NIC) {
607 			PMD_DRV_LOG(ERR, "Unsupported aead CHACHA20_POLY1305 algorithm!");
608 			return -EINVAL;
609 		}
610 
611 		if (aead->digest_length != 16) {
612 			PMD_DRV_LOG(ERR, "ICV must be 128bit with RTE_CRYPTO_AEAD_CHACHA20_POLY1305");
613 			return -EINVAL;
614 		}
615 
616 		/* Aead->alg_key_len includes 32-bit salt */
617 		if (key_length != 32) {
618 			PMD_DRV_LOG(ERR, "Unsupported CHACHA20 key length");
619 			return -EINVAL;
620 		}
621 
622 		/* The CHACHA20's mode is not configured */
623 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_POLY1305_128;
624 		cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_CHACHA20;
625 		break;
626 	default:
627 		PMD_DRV_LOG(ERR, "Unsupported aead algorithm!");
628 		return -EINVAL;
629 	}
630 
631 	key = (const uint32_t *)(aead->key.data);
632 
633 	/*
634 	 * The CHACHA20's key order needs to be adjusted based on hardware design.
635 	 * Unadjusted order: {K0, K1, K2, K3, K4, K5, K6, K7}
636 	 * Adjusted order: {K4, K5, K6, K7, K0, K1, K2, K3}
637 	 */
638 	if (aead->algo == RTE_CRYPTO_AEAD_CHACHA20_POLY1305)
639 		offset = key_length / sizeof(cfg->cipher_key[0]) << 1;
640 
641 	for (i = 0; i < key_length / sizeof(cfg->cipher_key[0]); i++) {
642 		index = (i + offset) % (key_length / sizeof(cfg->cipher_key[0]));
643 		cfg->cipher_key[index] = rte_cpu_to_be_32(*key++);
644 	}
645 
646 	/*
647 	 * The iv of the FW is equal to ESN by default. Reading the
648 	 * iv of the configuration information is not supported.
649 	 */
650 	iv_str = getenv("ETH_SEC_IV_OVR");
651 	if (iv_str != NULL) {
652 		iv_len = aead->iv.length;
653 		nfp_aesgcm_iv_update(cfg, iv_len, iv_str);
654 	}
655 
656 	return 0;
657 }
658 
659 /* Map rte_security_session_conf cipher algo to NFP cipher algo */
660 static int
661 nfp_cipher_map(struct rte_eth_dev *eth_dev,
662 		struct rte_crypto_cipher_xform *cipher,
663 		uint32_t key_length,
664 		struct ipsec_add_sa *cfg)
665 {
666 	int ret;
667 	uint32_t i;
668 	uint32_t device_id;
669 	const uint32_t *key;
670 	struct nfp_net_hw *net_hw;
671 
672 	net_hw = eth_dev->data->dev_private;
673 	device_id = net_hw->device_id;
674 
675 	switch (cipher->algo) {
676 	case RTE_CRYPTO_CIPHER_NULL:
677 		cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CBC;
678 		cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_NULL;
679 		break;
680 	case RTE_CRYPTO_CIPHER_3DES_CBC:
681 		if (device_id == PCI_DEVICE_ID_NFP3800_PF_NIC) {
682 			PMD_DRV_LOG(ERR, "Unsupported 3DESCBC encryption algorithm!");
683 			return -EINVAL;
684 		}
685 
686 		cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CBC;
687 		cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_3DES;
688 		break;
689 	case RTE_CRYPTO_CIPHER_AES_CBC:
690 		cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CBC;
691 		ret = set_aes_keylen(key_length, cfg);
692 		if (ret < 0) {
693 			PMD_DRV_LOG(ERR, "Failed to set cipher key length!");
694 			return -EINVAL;
695 		}
696 
697 		break;
698 	default:
699 		PMD_DRV_LOG(ERR, "Unsupported cipher alg!");
700 		return -EINVAL;
701 	}
702 
703 	key = (const uint32_t  *)(cipher->key.data);
704 	if (key_length > sizeof(cfg->cipher_key)) {
705 		PMD_DRV_LOG(ERR, "Insufficient space for offloaded key");
706 		return -EINVAL;
707 	}
708 
709 	for (i = 0; i < key_length / sizeof(cfg->cipher_key[0]); i++)
710 		cfg->cipher_key[i] = rte_cpu_to_be_32(*key++);
711 
712 	return 0;
713 }
714 
715 static void
716 set_md5hmac(struct ipsec_add_sa *cfg,
717 		uint32_t *digest_length)
718 {
719 	switch (*digest_length) {
720 	case 96:
721 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_MD5_96;
722 		break;
723 	case 128:
724 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_MD5_128;
725 		break;
726 	default:
727 		*digest_length = 0;
728 	}
729 }
730 
731 static void
732 set_sha1hmac(struct ipsec_add_sa *cfg,
733 		uint32_t *digest_length)
734 {
735 	switch (*digest_length) {
736 	case 96:
737 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA1_96;
738 		break;
739 	case 80:
740 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA1_80;
741 		break;
742 	default:
743 		*digest_length = 0;
744 	}
745 }
746 
747 static void
748 set_sha2_256hmac(struct ipsec_add_sa *cfg,
749 		uint32_t *digest_length)
750 {
751 	switch (*digest_length) {
752 	case 96:
753 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA256_96;
754 		break;
755 	case 128:
756 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA256_128;
757 		break;
758 	default:
759 		*digest_length = 0;
760 	}
761 }
762 
763 static void
764 set_sha2_384hmac(struct ipsec_add_sa *cfg,
765 		uint32_t *digest_length)
766 {
767 	switch (*digest_length) {
768 	case 96:
769 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA384_96;
770 		break;
771 	case 192:
772 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA384_192;
773 		break;
774 	default:
775 		*digest_length = 0;
776 	}
777 }
778 
779 static void
780 set_sha2_512hmac(struct ipsec_add_sa *cfg,
781 		uint32_t *digest_length)
782 {
783 	switch (*digest_length) {
784 	case 96:
785 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA512_96;
786 		break;
787 	case 256:
788 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA512_256;
789 		break;
790 	default:
791 		*digest_length = 0;
792 	}
793 }
794 
795 /* Map rte_security_session_conf auth algo to NFP auth algo */
796 static int
797 nfp_auth_map(struct rte_eth_dev *eth_dev,
798 		struct rte_crypto_auth_xform *auth,
799 		uint32_t digest_length,
800 		struct ipsec_add_sa *cfg)
801 {
802 	uint32_t i;
803 	uint8_t key_length;
804 	uint32_t device_id;
805 	const uint32_t *key;
806 	struct nfp_net_hw *net_hw;
807 
808 	if (digest_length == 0) {
809 		PMD_DRV_LOG(ERR, "Auth digest length is illegal!");
810 		return -EINVAL;
811 	}
812 
813 	net_hw = eth_dev->data->dev_private;
814 	device_id = net_hw->device_id;
815 	digest_length = digest_length << 3;
816 
817 	switch (auth->algo) {
818 	case RTE_CRYPTO_AUTH_NULL:
819 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_NONE;
820 		digest_length = 1;
821 		break;
822 	case RTE_CRYPTO_AUTH_MD5_HMAC:
823 		if (device_id == PCI_DEVICE_ID_NFP3800_PF_NIC) {
824 			PMD_DRV_LOG(ERR, "Unsupported MD5HMAC authentication algorithm!");
825 			return -EINVAL;
826 		}
827 
828 		set_md5hmac(cfg, &digest_length);
829 		break;
830 	case RTE_CRYPTO_AUTH_SHA1_HMAC:
831 		set_sha1hmac(cfg, &digest_length);
832 		break;
833 	case RTE_CRYPTO_AUTH_SHA256_HMAC:
834 		set_sha2_256hmac(cfg, &digest_length);
835 		break;
836 	case RTE_CRYPTO_AUTH_SHA384_HMAC:
837 		set_sha2_384hmac(cfg, &digest_length);
838 		break;
839 	case RTE_CRYPTO_AUTH_SHA512_HMAC:
840 		set_sha2_512hmac(cfg, &digest_length);
841 		break;
842 	default:
843 		PMD_DRV_LOG(ERR, "Unsupported auth alg!");
844 		return -EINVAL;
845 	}
846 
847 	if (digest_length == 0) {
848 		PMD_DRV_LOG(ERR, "Unsupported authentication algorithm digest length");
849 		return -EINVAL;
850 	}
851 
852 	key = (const uint32_t *)(auth->key.data);
853 	key_length = auth->key.length;
854 	if (key_length > sizeof(cfg->auth_key)) {
855 		PMD_DRV_LOG(ERR, "Insufficient space for offloaded auth key!");
856 		return -EINVAL;
857 	}
858 
859 	for (i = 0; i < key_length / sizeof(cfg->auth_key[0]); i++)
860 		cfg->auth_key[i] = rte_cpu_to_be_32(*key++);
861 
862 	return 0;
863 }
864 
865 static int
866 nfp_crypto_msg_build(struct rte_eth_dev *eth_dev,
867 		struct rte_security_session_conf *conf,
868 		struct nfp_ipsec_msg *msg)
869 {
870 	int ret;
871 	struct ipsec_add_sa *cfg;
872 	struct rte_crypto_sym_xform *cur;
873 	struct rte_crypto_sym_xform *next;
874 	enum rte_security_ipsec_sa_direction direction;
875 
876 	cur = conf->crypto_xform;
877 	if (cur == NULL) {
878 		PMD_DRV_LOG(ERR, "Unsupported crypto_xform is NULL!");
879 		return -EINVAL;
880 	}
881 
882 	next = cur->next;
883 	direction = conf->ipsec.direction;
884 	cfg = &msg->cfg_add_sa;
885 
886 	switch (cur->type) {
887 	case RTE_CRYPTO_SYM_XFORM_AEAD:
888 		/* Aead transforms can be used for either inbound/outbound IPsec SAs */
889 		if (next != NULL) {
890 			PMD_DRV_LOG(ERR, "Next crypto_xform type should be NULL!");
891 			return -EINVAL;
892 		}
893 
894 		ret = nfp_aead_map(eth_dev, &cur->aead, cur->aead.key.length, cfg);
895 		if (ret < 0) {
896 			PMD_DRV_LOG(ERR, "Failed to map aead alg!");
897 			return ret;
898 		}
899 
900 		cfg->aesgcm_fields.salt = rte_cpu_to_be_32(conf->ipsec.salt);
901 		break;
902 	case RTE_CRYPTO_SYM_XFORM_AUTH:
903 		/* Only support Auth + Cipher for inbound */
904 		if (direction != RTE_SECURITY_IPSEC_SA_DIR_INGRESS) {
905 			PMD_DRV_LOG(ERR, "Direction should be INGRESS, but it is not!");
906 			return -EINVAL;
907 		}
908 
909 		if (next == NULL || next->type != RTE_CRYPTO_SYM_XFORM_CIPHER) {
910 			PMD_DRV_LOG(ERR, "Next crypto_xfrm should be cipher, but it is not!");
911 			return -EINVAL;
912 		}
913 
914 		ret = nfp_auth_map(eth_dev, &cur->auth, cur->auth.digest_length, cfg);
915 		if (ret < 0) {
916 			PMD_DRV_LOG(ERR, "Failed to map auth alg!");
917 			return ret;
918 		}
919 
920 		ret = nfp_cipher_map(eth_dev, &next->cipher, next->cipher.key.length, cfg);
921 		if (ret < 0) {
922 			PMD_DRV_LOG(ERR, "Failed to map cipher alg!");
923 			return ret;
924 		}
925 
926 		break;
927 	case RTE_CRYPTO_SYM_XFORM_CIPHER:
928 		/* Only support Cipher + Auth for outbound */
929 		if (direction != RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
930 			PMD_DRV_LOG(ERR, "Direction should be EGRESS, but it is not!");
931 			return -EINVAL;
932 		}
933 
934 		if (next == NULL || next->type != RTE_CRYPTO_SYM_XFORM_AUTH) {
935 			PMD_DRV_LOG(ERR, "Next crypto_xfrm should be auth, but it is not!");
936 			return -EINVAL;
937 		}
938 
939 		ret = nfp_cipher_map(eth_dev, &cur->cipher, cur->cipher.key.length, cfg);
940 		if (ret < 0) {
941 			PMD_DRV_LOG(ERR, "Failed to map cipher alg!");
942 			return ret;
943 		}
944 
945 		ret = nfp_auth_map(eth_dev, &next->auth, next->auth.digest_length, cfg);
946 		if (ret < 0) {
947 			PMD_DRV_LOG(ERR, "Failed to map auth alg!");
948 			return ret;
949 		}
950 
951 		break;
952 	default:
953 		PMD_DRV_LOG(ERR, "Unsupported crypto_xform type!");
954 		return -EINVAL;
955 	}
956 
957 	return 0;
958 }
959 
960 static int
961 nfp_ipsec_msg_build(struct rte_eth_dev *eth_dev,
962 		struct rte_security_session_conf *conf,
963 		struct nfp_ipsec_msg *msg)
964 {
965 	int ret;
966 	struct ipsec_add_sa *cfg;
967 	enum rte_security_ipsec_tunnel_type type;
968 
969 	cfg = &msg->cfg_add_sa;
970 	cfg->spi = conf->ipsec.spi;
971 	cfg->pmtu_limit = 0xffff;
972 
973 	/*
974 	 * UDP encapsulation
975 	 *
976 	 * 1: Do UDP encapsulation/decapsulation
977 	 * 0: No UDP encapsulation
978 	 */
979 	if (conf->ipsec.options.udp_encap == 1) {
980 		cfg->udp_enable = 1;
981 		cfg->natt_dst_port = NFP_UDP_ESP_PORT;
982 		cfg->natt_src_port = NFP_UDP_ESP_PORT;
983 	}
984 
985 	if (conf->ipsec.options.copy_df == 1)
986 		cfg->df_ctrl = NFP_IPSEC_DF_COPY;
987 	else if (conf->ipsec.tunnel.ipv4.df != 0)
988 		cfg->df_ctrl = NFP_IPSEC_DF_SET;
989 	else
990 		cfg->df_ctrl = NFP_IPSEC_DF_CLEAR;
991 
992 	switch (conf->action_type) {
993 	case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO:
994 		cfg->ctrl_word.encap_dsbl = 1;
995 		break;
996 	case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL:
997 		cfg->ctrl_word.encap_dsbl = 0;
998 		break;
999 	default:
1000 		PMD_DRV_LOG(ERR, "Unsupported IPsec action for offload, action: %d",
1001 				conf->action_type);
1002 		return -EINVAL;
1003 	}
1004 
1005 	switch (conf->ipsec.proto) {
1006 	case RTE_SECURITY_IPSEC_SA_PROTO_ESP:
1007 		cfg->ctrl_word.proto = NFP_IPSEC_PROTOCOL_ESP;
1008 		break;
1009 	case RTE_SECURITY_IPSEC_SA_PROTO_AH:
1010 		cfg->ctrl_word.proto = NFP_IPSEC_PROTOCOL_AH;
1011 		break;
1012 	default:
1013 		PMD_DRV_LOG(ERR, "Unsupported IPsec protocol for offload, protocol: %d",
1014 				conf->ipsec.proto);
1015 		return -EINVAL;
1016 	}
1017 
1018 	switch (conf->ipsec.mode) {
1019 	case RTE_SECURITY_IPSEC_SA_MODE_TUNNEL:
1020 		type = conf->ipsec.tunnel.type;
1021 		cfg->ctrl_word.mode = NFP_IPSEC_MODE_TUNNEL;
1022 		if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV4) {
1023 			cfg->src_ip.v4 = conf->ipsec.tunnel.ipv4.src_ip;
1024 			cfg->dst_ip.v4 = conf->ipsec.tunnel.ipv4.dst_ip;
1025 			cfg->ipv6 = 0;
1026 		} else if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV6) {
1027 			cfg->src_ip.v6 = conf->ipsec.tunnel.ipv6.src_addr;
1028 			cfg->dst_ip.v6 = conf->ipsec.tunnel.ipv6.dst_addr;
1029 			cfg->ipv6 = 1;
1030 		} else {
1031 			PMD_DRV_LOG(ERR, "Unsupported address family!");
1032 			return -EINVAL;
1033 		}
1034 
1035 		break;
1036 	case RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT:
1037 		type = conf->ipsec.tunnel.type;
1038 		cfg->ctrl_word.mode = NFP_IPSEC_MODE_TRANSPORT;
1039 		if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV4) {
1040 			memset(&cfg->src_ip, 0, sizeof(cfg->src_ip));
1041 			cfg->ipv6 = 0;
1042 		} else if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV6) {
1043 			memset(&cfg->src_ip, 0, sizeof(cfg->src_ip));
1044 			cfg->ipv6 = 1;
1045 		} else {
1046 			PMD_DRV_LOG(ERR, "Unsupported address family!");
1047 			return -EINVAL;
1048 		}
1049 
1050 		break;
1051 	default:
1052 		PMD_DRV_LOG(ERR, "Unsupported IPsec mode for offload, mode: %d",
1053 				conf->ipsec.mode);
1054 		return -EINVAL;
1055 	}
1056 
1057 	ret = nfp_crypto_msg_build(eth_dev, conf, msg);
1058 	if (ret < 0) {
1059 		PMD_DRV_LOG(ERR, "Failed to build auth/crypto/aead msg!");
1060 		return ret;
1061 	}
1062 
1063 	return 0;
1064 }
1065 
1066 static int
1067 nfp_crypto_create_session(void *device,
1068 		struct rte_security_session_conf *conf,
1069 		struct rte_security_session *session)
1070 {
1071 	int ret;
1072 	int sa_idx;
1073 	struct nfp_net_hw *net_hw;
1074 	struct nfp_ipsec_msg msg;
1075 	struct rte_eth_dev *eth_dev;
1076 	struct nfp_ipsec_session *priv_session;
1077 
1078 	/* Only support IPsec at present */
1079 	if (conf->protocol != RTE_SECURITY_PROTOCOL_IPSEC) {
1080 		PMD_DRV_LOG(ERR, "Unsupported non-IPsec offload!");
1081 		return -EINVAL;
1082 	}
1083 
1084 	sa_idx = -1;
1085 	eth_dev = device;
1086 	priv_session = SECURITY_GET_SESS_PRIV(session);
1087 	net_hw = eth_dev->data->dev_private;
1088 
1089 	if (net_hw->ipsec_data->sa_free_cnt == 0) {
1090 		PMD_DRV_LOG(ERR, "No space in SA table, spi: %d", conf->ipsec.spi);
1091 		return -EINVAL;
1092 	}
1093 
1094 	nfp_get_sa_entry(net_hw->ipsec_data, &sa_idx);
1095 
1096 	if (sa_idx < 0) {
1097 		PMD_DRV_LOG(ERR, "Failed to get SA entry!");
1098 		return -EINVAL;
1099 	}
1100 
1101 	memset(&msg, 0, sizeof(msg));
1102 	ret = nfp_ipsec_msg_build(eth_dev, conf, &msg);
1103 	if (ret < 0) {
1104 		PMD_DRV_LOG(ERR, "Failed to build IPsec msg!");
1105 		return -EINVAL;
1106 	}
1107 
1108 	msg.cmd = NFP_IPSEC_CFG_MSG_ADD_SA;
1109 	msg.sa_idx = sa_idx;
1110 	ret = nfp_ipsec_cfg_cmd_issue(net_hw, &msg);
1111 	if (ret < 0) {
1112 		PMD_DRV_LOG(ERR, "Failed to add SA to nic");
1113 		return -EINVAL;
1114 	}
1115 
1116 	priv_session->action = conf->action_type;
1117 	priv_session->ipsec = conf->ipsec;
1118 	priv_session->msg = msg.cfg_add_sa;
1119 	priv_session->sa_index = sa_idx;
1120 	priv_session->dev = eth_dev;
1121 	priv_session->user_data = conf->userdata;
1122 
1123 	net_hw->ipsec_data->sa_free_cnt--;
1124 	net_hw->ipsec_data->sa_entries[sa_idx] = priv_session;
1125 
1126 	return 0;
1127 }
1128 
1129 static int
1130 nfp_crypto_update_session(void *device __rte_unused,
1131 		struct rte_security_session *session,
1132 		struct rte_security_session_conf *conf)
1133 {
1134 	struct nfp_ipsec_session *priv_session;
1135 
1136 	priv_session = SECURITY_GET_SESS_PRIV(session);
1137 	if (priv_session == NULL)
1138 		return -EINVAL;
1139 
1140 	/* Update IPsec ESN value */
1141 	if (priv_session->msg.ctrl_word.ext_seq != 0 && conf->ipsec.options.esn != 0) {
1142 		/*
1143 		 * Store in nfp_ipsec_session for outbound SA for use
1144 		 * in nfp_security_set_pkt_metadata() function.
1145 		 */
1146 		priv_session->ipsec.esn.hi = conf->ipsec.esn.hi;
1147 		priv_session->ipsec.esn.low = conf->ipsec.esn.low;
1148 	}
1149 
1150 	return 0;
1151 }
1152 
1153 static int
1154 nfp_security_set_pkt_metadata(void *device,
1155 		struct rte_security_session *session,
1156 		struct rte_mbuf *m,
1157 		void *params)
1158 {
1159 	int offset;
1160 	uint64_t *sqn;
1161 	struct nfp_net_hw *net_hw;
1162 	struct rte_eth_dev *eth_dev;
1163 	struct nfp_ipsec_session *priv_session;
1164 
1165 	sqn = params;
1166 	eth_dev = device;
1167 	priv_session = SECURITY_GET_SESS_PRIV(session);
1168 	net_hw = eth_dev->data->dev_private;
1169 
1170 	if (priv_session->ipsec.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
1171 		struct nfp_tx_ipsec_desc_msg *desc_md;
1172 
1173 		offset = net_hw->ipsec_data->pkt_dynfield_offset;
1174 		desc_md = RTE_MBUF_DYNFIELD(m, offset, struct nfp_tx_ipsec_desc_msg *);
1175 
1176 		if (priv_session->msg.ctrl_word.ext_seq != 0 && sqn != NULL) {
1177 			desc_md->esn.low = rte_cpu_to_be_32(*sqn);
1178 			desc_md->esn.hi = rte_cpu_to_be_32(*sqn >> 32);
1179 		} else if (priv_session->msg.ctrl_word.ext_seq != 0) {
1180 			desc_md->esn.low = rte_cpu_to_be_32(priv_session->ipsec.esn.low);
1181 			desc_md->esn.hi = rte_cpu_to_be_32(priv_session->ipsec.esn.hi);
1182 		} else {
1183 			desc_md->esn.low = rte_cpu_to_be_32(priv_session->ipsec.esn.value);
1184 			desc_md->esn.hi = 0;
1185 		}
1186 
1187 		desc_md->enc = 1;
1188 		desc_md->sa_idx = rte_cpu_to_be_32(priv_session->sa_index);
1189 	}
1190 
1191 	return 0;
1192 }
1193 
1194 /**
1195  * Get discards packet statistics for each SA
1196  *
1197  * The sa_discard_stats contains the statistics of discards packets
1198  * of an SA. This function calculates the sum total of discarded packets.
1199  *
1200  * @param errors
1201  *   The value is SA discards packet sum total
1202  * @param sa_discard_stats
1203  *   The struct is SA discards packet Statistics
1204  */
1205 static void
1206 nfp_get_errorstats(uint64_t *errors,
1207 		struct ipsec_discard_stats *sa_discard_stats)
1208 {
1209 	uint32_t i;
1210 	uint32_t len;
1211 	uint32_t *perror;
1212 
1213 	perror = &sa_discard_stats->discards_auth;
1214 	len = sizeof(struct ipsec_discard_stats) / sizeof(uint32_t);
1215 
1216 	for (i = 0; i < len; i++)
1217 		*errors += *perror++;
1218 
1219 	*errors -= sa_discard_stats->ipv4_id_counter;
1220 }
1221 
1222 static int
1223 nfp_security_session_get_stats(void *device,
1224 		struct rte_security_session *session,
1225 		struct rte_security_stats *stats)
1226 {
1227 	int ret;
1228 	struct nfp_net_hw *net_hw;
1229 	struct nfp_ipsec_msg msg;
1230 	struct rte_eth_dev *eth_dev;
1231 	struct ipsec_get_sa_stats *cfg_s;
1232 	struct rte_security_ipsec_stats *ips_s;
1233 	struct nfp_ipsec_session *priv_session;
1234 	enum rte_security_ipsec_sa_direction direction;
1235 
1236 	eth_dev = device;
1237 	priv_session = SECURITY_GET_SESS_PRIV(session);
1238 	memset(&msg, 0, sizeof(msg));
1239 	msg.cmd = NFP_IPSEC_CFG_MSG_GET_SA_STATS;
1240 	msg.sa_idx = priv_session->sa_index;
1241 	net_hw = eth_dev->data->dev_private;
1242 
1243 	ret = nfp_ipsec_cfg_cmd_issue(net_hw, &msg);
1244 	if (ret < 0) {
1245 		PMD_DRV_LOG(ERR, "Failed to get SA stats");
1246 		return ret;
1247 	}
1248 
1249 	cfg_s = &msg.cfg_get_stats;
1250 	direction = priv_session->ipsec.direction;
1251 	memset(stats, 0, sizeof(struct rte_security_stats)); /* Start with zeros */
1252 	stats->protocol = RTE_SECURITY_PROTOCOL_IPSEC;
1253 	ips_s = &stats->ipsec;
1254 
1255 	/* Only display SA if any counters are non-zero */
1256 	if (cfg_s->lifetime_byte_count != 0 || cfg_s->pkt_count != 0) {
1257 		if (direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) {
1258 			ips_s->ipackets = cfg_s->pkt_count;
1259 			ips_s->ibytes = cfg_s->lifetime_byte_count;
1260 			nfp_get_errorstats(&ips_s->ierrors, &cfg_s->sa_discard_stats);
1261 		} else {
1262 			ips_s->opackets = cfg_s->pkt_count;
1263 			ips_s->obytes = cfg_s->lifetime_byte_count;
1264 			nfp_get_errorstats(&ips_s->oerrors, &cfg_s->sa_discard_stats);
1265 		}
1266 	}
1267 
1268 	return 0;
1269 }
1270 
1271 static const struct rte_security_capability *
1272 nfp_crypto_capabilities_get(void *device __rte_unused)
1273 {
1274 	return nfp_security_caps;
1275 }
1276 
1277 static uint32_t
1278 nfp_security_session_get_size(void *device __rte_unused)
1279 {
1280 	return sizeof(struct nfp_ipsec_session);
1281 }
1282 
1283 static int
1284 nfp_crypto_remove_sa(struct rte_eth_dev *eth_dev,
1285 		struct nfp_ipsec_session *priv_session)
1286 {
1287 	int ret;
1288 	uint32_t sa_index;
1289 	struct nfp_net_hw *net_hw;
1290 	struct nfp_ipsec_msg cfg;
1291 
1292 	sa_index = priv_session->sa_index;
1293 	net_hw = eth_dev->data->dev_private;
1294 
1295 	cfg.cmd = NFP_IPSEC_CFG_MSG_INV_SA;
1296 	cfg.sa_idx = sa_index;
1297 	ret = nfp_ipsec_cfg_cmd_issue(net_hw, &cfg);
1298 	if (ret < 0) {
1299 		PMD_DRV_LOG(ERR, "Failed to remove SA!");
1300 		return -EINVAL;
1301 	}
1302 
1303 	net_hw->ipsec_data->sa_free_cnt++;
1304 	net_hw->ipsec_data->sa_entries[sa_index] = NULL;
1305 
1306 	return 0;
1307 }
1308 
1309 static int
1310 nfp_crypto_remove_session(void *device,
1311 		struct rte_security_session *session)
1312 {
1313 	int ret;
1314 	struct rte_eth_dev *eth_dev;
1315 	struct nfp_ipsec_session *priv_session;
1316 
1317 	eth_dev = device;
1318 	priv_session = SECURITY_GET_SESS_PRIV(session);
1319 	if (eth_dev != priv_session->dev) {
1320 		PMD_DRV_LOG(ERR, "Session not bound to this device");
1321 		return -ENODEV;
1322 	}
1323 
1324 	ret = nfp_crypto_remove_sa(eth_dev, priv_session);
1325 	if (ret < 0) {
1326 		PMD_DRV_LOG(ERR, "Failed to remove session");
1327 		return -EFAULT;
1328 	}
1329 
1330 	memset(priv_session, 0, sizeof(struct nfp_ipsec_session));
1331 
1332 	return 0;
1333 }
1334 
1335 static const struct rte_security_ops nfp_security_ops = {
1336 	.session_create = nfp_crypto_create_session,
1337 	.session_update = nfp_crypto_update_session,
1338 	.session_get_size = nfp_security_session_get_size,
1339 	.session_stats_get = nfp_security_session_get_stats,
1340 	.session_destroy = nfp_crypto_remove_session,
1341 	.set_pkt_metadata = nfp_security_set_pkt_metadata,
1342 	.capabilities_get = nfp_crypto_capabilities_get,
1343 };
1344 
1345 static int
1346 nfp_ipsec_ctx_create(struct rte_eth_dev *dev,
1347 		struct nfp_net_ipsec_data *data)
1348 {
1349 	struct rte_security_ctx *ctx;
1350 	static const struct rte_mbuf_dynfield pkt_md_dynfield = {
1351 		.name = "nfp_ipsec_crypto_pkt_metadata",
1352 		.size = sizeof(struct nfp_tx_ipsec_desc_msg),
1353 		.align = alignof(struct nfp_tx_ipsec_desc_msg),
1354 	};
1355 
1356 	ctx = rte_zmalloc("security_ctx",
1357 			sizeof(struct rte_security_ctx), 0);
1358 	if (ctx == NULL) {
1359 		PMD_INIT_LOG(ERR, "Failed to malloc security_ctx");
1360 		return -ENOMEM;
1361 	}
1362 
1363 	ctx->device = dev;
1364 	ctx->ops = &nfp_security_ops;
1365 	ctx->sess_cnt = 0;
1366 	dev->security_ctx = ctx;
1367 
1368 	data->pkt_dynfield_offset = rte_mbuf_dynfield_register(&pkt_md_dynfield);
1369 	if (data->pkt_dynfield_offset < 0) {
1370 		PMD_INIT_LOG(ERR, "Failed to register mbuf esn_dynfield");
1371 		return -ENOMEM;
1372 	}
1373 
1374 	return 0;
1375 }
1376 
1377 int
1378 nfp_ipsec_init(struct rte_eth_dev *dev)
1379 {
1380 	int ret;
1381 	uint32_t cap_extend;
1382 	struct nfp_net_hw *net_hw;
1383 	struct nfp_net_ipsec_data *data;
1384 
1385 	net_hw = dev->data->dev_private;
1386 
1387 	cap_extend = net_hw->super.cap_ext;
1388 	if ((cap_extend & NFP_NET_CFG_CTRL_IPSEC) == 0) {
1389 		PMD_INIT_LOG(INFO, "Unsupported IPsec extend capability");
1390 		return 0;
1391 	}
1392 
1393 	data = rte_zmalloc("ipsec_data", sizeof(struct nfp_net_ipsec_data), 0);
1394 	if (data == NULL) {
1395 		PMD_INIT_LOG(ERR, "Failed to malloc ipsec_data");
1396 		return -ENOMEM;
1397 	}
1398 
1399 	data->pkt_dynfield_offset = -1;
1400 	data->sa_free_cnt = NFP_NET_IPSEC_MAX_SA_CNT;
1401 	net_hw->ipsec_data = data;
1402 
1403 	ret = nfp_ipsec_ctx_create(dev, data);
1404 	if (ret != 0) {
1405 		PMD_INIT_LOG(ERR, "Failed to create IPsec ctx");
1406 		goto ipsec_cleanup;
1407 	}
1408 
1409 	return 0;
1410 
1411 ipsec_cleanup:
1412 	nfp_ipsec_uninit(dev);
1413 
1414 	return ret;
1415 }
1416 
1417 static void
1418 nfp_ipsec_ctx_destroy(struct rte_eth_dev *dev)
1419 {
1420 	rte_free(dev->security_ctx);
1421 }
1422 
1423 void
1424 nfp_ipsec_uninit(struct rte_eth_dev *dev)
1425 {
1426 	uint16_t i;
1427 	uint32_t cap_extend;
1428 	struct nfp_net_hw *net_hw;
1429 	struct nfp_ipsec_session *priv_session;
1430 
1431 	net_hw = dev->data->dev_private;
1432 
1433 	cap_extend = net_hw->super.cap_ext;
1434 	if ((cap_extend & NFP_NET_CFG_CTRL_IPSEC) == 0) {
1435 		PMD_INIT_LOG(INFO, "Unsupported IPsec extend capability");
1436 		return;
1437 	}
1438 
1439 	nfp_ipsec_ctx_destroy(dev);
1440 
1441 	if (net_hw->ipsec_data == NULL) {
1442 		PMD_INIT_LOG(INFO, "IPsec data is NULL!");
1443 		return;
1444 	}
1445 
1446 	for (i = 0; i < NFP_NET_IPSEC_MAX_SA_CNT; i++) {
1447 		priv_session = net_hw->ipsec_data->sa_entries[i];
1448 		if (priv_session != NULL)
1449 			memset(priv_session, 0, sizeof(struct nfp_ipsec_session));
1450 	}
1451 
1452 	rte_free(net_hw->ipsec_data);
1453 }
1454 
1455