xref: /dpdk/drivers/net/nfp/nfp_ipsec.c (revision b6de43530dfa30cbf6b70857e3835099701063d4)
154713740SChang Miao /* SPDX-License-Identifier: BSD-3-Clause
254713740SChang Miao  * Copyright (c) 2023 Corigine Systems, Inc.
354713740SChang Miao  * All rights reserved.
454713740SChang Miao  */
554713740SChang Miao 
608966fe7STyler Retzlaff #include <stdalign.h>
708966fe7STyler Retzlaff 
854713740SChang Miao #include "nfp_ipsec.h"
954713740SChang Miao 
10e6d69ea0SShihong Wang #include <rte_cryptodev.h>
1154713740SChang Miao #include <rte_malloc.h>
1254713740SChang Miao #include <rte_security_driver.h>
1354713740SChang Miao 
1454713740SChang Miao #include <ethdev_driver.h>
1554713740SChang Miao #include <ethdev_pci.h>
1654713740SChang Miao 
1754713740SChang Miao #include "nfp_logs.h"
1811e9eae4SChaoyong He #include "nfp_net_common.h"
19e2018e37SChaoyong He #include "nfp_net_ctrl.h"
2054713740SChang Miao #include "nfp_rxtx.h"
21ddcd598fSLong Wu #include "nfp_net_meta.h"
2254713740SChang Miao 
233d21da66SChang Miao #define NFP_UDP_ESP_PORT            4500
247e13f2dcSShihong Wang #define NFP_ESP_IV_LENGTH           8
253d21da66SChang Miao 
26e6d69ea0SShihong Wang static const struct rte_cryptodev_capabilities nfp_crypto_caps[] = {
27e6d69ea0SShihong Wang 	{
28e6d69ea0SShihong Wang 		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
29e6d69ea0SShihong Wang 		.sym = {
30e6d69ea0SShihong Wang 			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
31e6d69ea0SShihong Wang 			.auth = {
32e6d69ea0SShihong Wang 				.algo = RTE_CRYPTO_AUTH_MD5_HMAC,
33e6d69ea0SShihong Wang 				.block_size = 64,
34e6d69ea0SShihong Wang 				.key_size = {
35e6d69ea0SShihong Wang 					.min = 16,
36e6d69ea0SShihong Wang 					.max = 16,
37e6d69ea0SShihong Wang 					.increment = 0
38e6d69ea0SShihong Wang 				},
39e6d69ea0SShihong Wang 				.digest_size = {
40e6d69ea0SShihong Wang 					.min = 12,
41e6d69ea0SShihong Wang 					.max = 16,
42e6d69ea0SShihong Wang 					.increment = 4
43e6d69ea0SShihong Wang 				},
44e6d69ea0SShihong Wang 			},
45e6d69ea0SShihong Wang 		},
46e6d69ea0SShihong Wang 	},
47e6d69ea0SShihong Wang 	{
48e6d69ea0SShihong Wang 		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
49e6d69ea0SShihong Wang 		.sym = {
50e6d69ea0SShihong Wang 			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
51e6d69ea0SShihong Wang 			.auth = {
52e6d69ea0SShihong Wang 				.algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
53e6d69ea0SShihong Wang 				.block_size = 64,
54e6d69ea0SShihong Wang 				.key_size = {
55e6d69ea0SShihong Wang 					.min = 20,
56e6d69ea0SShihong Wang 					.max = 64,
57e6d69ea0SShihong Wang 					.increment = 1
58e6d69ea0SShihong Wang 				},
59e6d69ea0SShihong Wang 				.digest_size = {
60e6d69ea0SShihong Wang 					.min = 10,
61e6d69ea0SShihong Wang 					.max = 12,
62e6d69ea0SShihong Wang 					.increment = 2
63e6d69ea0SShihong Wang 				},
64e6d69ea0SShihong Wang 			},
65e6d69ea0SShihong Wang 		},
66e6d69ea0SShihong Wang 	},
67e6d69ea0SShihong Wang 	{
68e6d69ea0SShihong Wang 		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
69e6d69ea0SShihong Wang 		.sym = {
70e6d69ea0SShihong Wang 			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
71e6d69ea0SShihong Wang 			.auth = {
72e6d69ea0SShihong Wang 				.algo = RTE_CRYPTO_AUTH_SHA256_HMAC,
73e6d69ea0SShihong Wang 				.block_size = 64,
74e6d69ea0SShihong Wang 				.key_size = {
75e6d69ea0SShihong Wang 					.min = 32,
76e6d69ea0SShihong Wang 					.max = 32,
77e6d69ea0SShihong Wang 					.increment = 0
78e6d69ea0SShihong Wang 				},
79e6d69ea0SShihong Wang 				.digest_size = {
80e6d69ea0SShihong Wang 					.min = 12,
81e6d69ea0SShihong Wang 					.max = 16,
82e6d69ea0SShihong Wang 					.increment = 4
83e6d69ea0SShihong Wang 				},
84e6d69ea0SShihong Wang 			},
85e6d69ea0SShihong Wang 		},
86e6d69ea0SShihong Wang 	},
87e6d69ea0SShihong Wang 	{
88e6d69ea0SShihong Wang 		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
89e6d69ea0SShihong Wang 		.sym = {
90e6d69ea0SShihong Wang 			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
91e6d69ea0SShihong Wang 			.auth = {
92e6d69ea0SShihong Wang 				.algo = RTE_CRYPTO_AUTH_SHA384_HMAC,
93e6d69ea0SShihong Wang 				.block_size = 128,
94e6d69ea0SShihong Wang 				.key_size = {
95e6d69ea0SShihong Wang 					.min = 48,
96e6d69ea0SShihong Wang 					.max = 48,
97e6d69ea0SShihong Wang 					.increment = 0
98e6d69ea0SShihong Wang 				},
99e6d69ea0SShihong Wang 				.digest_size = {
100e6d69ea0SShihong Wang 					.min = 12,
101e6d69ea0SShihong Wang 					.max = 24,
102e6d69ea0SShihong Wang 					.increment = 12
103e6d69ea0SShihong Wang 				},
104e6d69ea0SShihong Wang 			},
105e6d69ea0SShihong Wang 		},
106e6d69ea0SShihong Wang 	},
107e6d69ea0SShihong Wang 	{
108e6d69ea0SShihong Wang 		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
109e6d69ea0SShihong Wang 		.sym = {
110e6d69ea0SShihong Wang 			.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
111e6d69ea0SShihong Wang 			.auth = {
112e6d69ea0SShihong Wang 				.algo = RTE_CRYPTO_AUTH_SHA512_HMAC,
113e6d69ea0SShihong Wang 				.block_size = 128,
114e6d69ea0SShihong Wang 				.key_size = {
115e6d69ea0SShihong Wang 					.min = 64,
116e6d69ea0SShihong Wang 					.max = 64,
117e6d69ea0SShihong Wang 					.increment = 1
118e6d69ea0SShihong Wang 				},
119e6d69ea0SShihong Wang 				.digest_size = {
120e6d69ea0SShihong Wang 					.min = 12,
121e6d69ea0SShihong Wang 					.max = 32,
122e6d69ea0SShihong Wang 					.increment = 4
123e6d69ea0SShihong Wang 				},
124e6d69ea0SShihong Wang 			},
125e6d69ea0SShihong Wang 		},
126e6d69ea0SShihong Wang 	},
127e6d69ea0SShihong Wang 	{
128e6d69ea0SShihong Wang 		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
129e6d69ea0SShihong Wang 		.sym = {
130e6d69ea0SShihong Wang 			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
131e6d69ea0SShihong Wang 			.cipher = {
132e6d69ea0SShihong Wang 				.algo = RTE_CRYPTO_CIPHER_3DES_CBC,
133e6d69ea0SShihong Wang 				.block_size = 8,
134e6d69ea0SShihong Wang 				.key_size = {
135e6d69ea0SShihong Wang 					.min = 24,
136e6d69ea0SShihong Wang 					.max = 24,
137e6d69ea0SShihong Wang 					.increment = 0
138e6d69ea0SShihong Wang 				},
139e6d69ea0SShihong Wang 				.iv_size = {
140e6d69ea0SShihong Wang 					.min = 8,
141e6d69ea0SShihong Wang 					.max = 16,
142e6d69ea0SShihong Wang 					.increment = 8
143e6d69ea0SShihong Wang 				},
144e6d69ea0SShihong Wang 			},
145e6d69ea0SShihong Wang 		},
146e6d69ea0SShihong Wang 	},
147e6d69ea0SShihong Wang 	{
148e6d69ea0SShihong Wang 		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
149e6d69ea0SShihong Wang 		.sym = {
150e6d69ea0SShihong Wang 			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
151e6d69ea0SShihong Wang 			.cipher = {
152e6d69ea0SShihong Wang 				.algo = RTE_CRYPTO_CIPHER_AES_CBC,
153e6d69ea0SShihong Wang 				.block_size = 16,
154e6d69ea0SShihong Wang 				.key_size = {
155e6d69ea0SShihong Wang 					.min = 16,
156e6d69ea0SShihong Wang 					.max = 32,
157e6d69ea0SShihong Wang 					.increment = 8
158e6d69ea0SShihong Wang 				},
159e6d69ea0SShihong Wang 				.iv_size = {
160e6d69ea0SShihong Wang 					.min = 8,
161e6d69ea0SShihong Wang 					.max = 16,
162e6d69ea0SShihong Wang 					.increment = 8
163e6d69ea0SShihong Wang 				},
164e6d69ea0SShihong Wang 			},
165e6d69ea0SShihong Wang 		},
166e6d69ea0SShihong Wang 	},
167e6d69ea0SShihong Wang 	{
168e6d69ea0SShihong Wang 		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
169e6d69ea0SShihong Wang 		.sym = {
170e6d69ea0SShihong Wang 			.xform_type = RTE_CRYPTO_SYM_XFORM_AEAD,
171e6d69ea0SShihong Wang 			.aead = {
172e6d69ea0SShihong Wang 				.algo = RTE_CRYPTO_AEAD_AES_GCM,
173e6d69ea0SShihong Wang 				.block_size = 16,
174e6d69ea0SShihong Wang 				.key_size = {
175e6d69ea0SShihong Wang 					.min = 16,
176e6d69ea0SShihong Wang 					.max = 32,
177e6d69ea0SShihong Wang 					.increment = 8
178e6d69ea0SShihong Wang 				},
179e6d69ea0SShihong Wang 				.digest_size = {
180e6d69ea0SShihong Wang 					.min = 16,
181e6d69ea0SShihong Wang 					.max = 16,
182e6d69ea0SShihong Wang 					.increment = 0
183e6d69ea0SShihong Wang 				},
184e6d69ea0SShihong Wang 				.aad_size = {
185e6d69ea0SShihong Wang 					.min = 0,
186e6d69ea0SShihong Wang 					.max = 1024,
187e6d69ea0SShihong Wang 					.increment = 1
188e6d69ea0SShihong Wang 				},
189e6d69ea0SShihong Wang 				.iv_size = {
190e6d69ea0SShihong Wang 					.min = 8,
191e6d69ea0SShihong Wang 					.max = 16,
192e6d69ea0SShihong Wang 					.increment = 4
193e6d69ea0SShihong Wang 				}
194e6d69ea0SShihong Wang 			},
195e6d69ea0SShihong Wang 		},
196e6d69ea0SShihong Wang 	},
197e6d69ea0SShihong Wang 	{
198e6d69ea0SShihong Wang 		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
199e6d69ea0SShihong Wang 		.sym = {
200e6d69ea0SShihong Wang 			.xform_type = RTE_CRYPTO_SYM_XFORM_AEAD,
201e6d69ea0SShihong Wang 			.aead = {
202e6d69ea0SShihong Wang 				.algo = RTE_CRYPTO_AEAD_CHACHA20_POLY1305,
203e6d69ea0SShihong Wang 				.block_size = 16,
204e6d69ea0SShihong Wang 				.key_size = {
205e6d69ea0SShihong Wang 					.min = 32,
206e6d69ea0SShihong Wang 					.max = 32,
207e6d69ea0SShihong Wang 					.increment = 0
208e6d69ea0SShihong Wang 				},
209e6d69ea0SShihong Wang 				.digest_size = {
210e6d69ea0SShihong Wang 					.min = 16,
211e6d69ea0SShihong Wang 					.max = 16,
212e6d69ea0SShihong Wang 					.increment = 0
213e6d69ea0SShihong Wang 				},
214e6d69ea0SShihong Wang 				.aad_size = {
215e6d69ea0SShihong Wang 					.min = 0,
216e6d69ea0SShihong Wang 					.max = 1024,
217e6d69ea0SShihong Wang 					.increment = 1
218e6d69ea0SShihong Wang 				},
219e6d69ea0SShihong Wang 				.iv_size = {
220e6d69ea0SShihong Wang 					.min = 8,
221e6d69ea0SShihong Wang 					.max = 16,
222e6d69ea0SShihong Wang 					.increment = 4
223e6d69ea0SShihong Wang 				}
224e6d69ea0SShihong Wang 			},
225e6d69ea0SShihong Wang 		},
226e6d69ea0SShihong Wang 	},
227e6d69ea0SShihong Wang 	{
228e6d69ea0SShihong Wang 		.op = RTE_CRYPTO_OP_TYPE_UNDEFINED,
229e6d69ea0SShihong Wang 		.sym = {
230e6d69ea0SShihong Wang 			.xform_type = RTE_CRYPTO_SYM_XFORM_NOT_SPECIFIED
231e6d69ea0SShihong Wang 		},
232e6d69ea0SShihong Wang 	}
233e6d69ea0SShihong Wang };
234e6d69ea0SShihong Wang 
235e6d69ea0SShihong Wang static const struct rte_security_capability nfp_security_caps[] = {
236e6d69ea0SShihong Wang 	{ /* IPsec Inline Crypto Tunnel Egress */
237e6d69ea0SShihong Wang 		.action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
238e6d69ea0SShihong Wang 		.protocol = RTE_SECURITY_PROTOCOL_IPSEC,
239e6d69ea0SShihong Wang 		.ipsec = {
240e6d69ea0SShihong Wang 			.mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL,
241e6d69ea0SShihong Wang 			.direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS,
242e6d69ea0SShihong Wang 			.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
243e6d69ea0SShihong Wang 			.options = {
244e6d69ea0SShihong Wang 				.udp_encap = 1,
245e6d69ea0SShihong Wang 				.stats = 1,
246e6d69ea0SShihong Wang 				.esn = 1
247e6d69ea0SShihong Wang 				}
248e6d69ea0SShihong Wang 		},
24968287e9bSShihong Wang 		.crypto_capabilities = nfp_crypto_caps,
25068287e9bSShihong Wang 		.ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA
251e6d69ea0SShihong Wang 	},
252e6d69ea0SShihong Wang 	{ /* IPsec Inline Crypto Tunnel Ingress */
253e6d69ea0SShihong Wang 		.action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
254e6d69ea0SShihong Wang 		.protocol = RTE_SECURITY_PROTOCOL_IPSEC,
255e6d69ea0SShihong Wang 		.ipsec = {
256e6d69ea0SShihong Wang 			.mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL,
257e6d69ea0SShihong Wang 			.direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS,
258e6d69ea0SShihong Wang 			.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
259e6d69ea0SShihong Wang 			.options = {
260e6d69ea0SShihong Wang 				.udp_encap = 1,
261e6d69ea0SShihong Wang 				.stats = 1,
262e6d69ea0SShihong Wang 				.esn = 1
263e6d69ea0SShihong Wang 				}
264e6d69ea0SShihong Wang 		},
26568287e9bSShihong Wang 		.crypto_capabilities = nfp_crypto_caps
266e6d69ea0SShihong Wang 	},
267e6d69ea0SShihong Wang 	{ /* IPsec Inline Crypto Transport Egress */
268e6d69ea0SShihong Wang 		.action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
269e6d69ea0SShihong Wang 		.protocol = RTE_SECURITY_PROTOCOL_IPSEC,
270e6d69ea0SShihong Wang 		.ipsec = {
271e6d69ea0SShihong Wang 			.mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
272e6d69ea0SShihong Wang 			.direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS,
273e6d69ea0SShihong Wang 			.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
274e6d69ea0SShihong Wang 			.options = {
275e6d69ea0SShihong Wang 				.udp_encap = 1,
276e6d69ea0SShihong Wang 				.stats = 1,
277e6d69ea0SShihong Wang 				.esn = 1
278e6d69ea0SShihong Wang 				}
279e6d69ea0SShihong Wang 		},
28068287e9bSShihong Wang 		.crypto_capabilities = nfp_crypto_caps,
28168287e9bSShihong Wang 		.ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA
282e6d69ea0SShihong Wang 	},
283e6d69ea0SShihong Wang 	{ /* IPsec Inline Crypto Transport Ingress */
284e6d69ea0SShihong Wang 		.action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
285e6d69ea0SShihong Wang 		.protocol = RTE_SECURITY_PROTOCOL_IPSEC,
286e6d69ea0SShihong Wang 		.ipsec = {
287e6d69ea0SShihong Wang 			.mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
288e6d69ea0SShihong Wang 			.direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS,
289e6d69ea0SShihong Wang 			.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
290e6d69ea0SShihong Wang 			.options = {
291e6d69ea0SShihong Wang 				.udp_encap = 1,
292e6d69ea0SShihong Wang 				.stats = 1,
293e6d69ea0SShihong Wang 				.esn = 1
294e6d69ea0SShihong Wang 				}
295e6d69ea0SShihong Wang 		},
29668287e9bSShihong Wang 		.crypto_capabilities = nfp_crypto_caps
297e6d69ea0SShihong Wang 	},
298e6d69ea0SShihong Wang 	{ /* IPsec Inline Protocol Tunnel Egress */
299e6d69ea0SShihong Wang 		.action = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL,
300e6d69ea0SShihong Wang 		.protocol = RTE_SECURITY_PROTOCOL_IPSEC,
301e6d69ea0SShihong Wang 		.ipsec = {
302e6d69ea0SShihong Wang 			.mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL,
303e6d69ea0SShihong Wang 			.direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS,
304e6d69ea0SShihong Wang 			.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
305e6d69ea0SShihong Wang 			.options = {
306e6d69ea0SShihong Wang 				.udp_encap = 1,
307e6d69ea0SShihong Wang 				.stats = 1,
308e6d69ea0SShihong Wang 				.esn = 1
309e6d69ea0SShihong Wang 				}
310e6d69ea0SShihong Wang 		},
31168287e9bSShihong Wang 		.crypto_capabilities = nfp_crypto_caps,
31268287e9bSShihong Wang 		.ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA
313e6d69ea0SShihong Wang 	},
314e6d69ea0SShihong Wang 	{ /* IPsec Inline Protocol Tunnel Ingress */
315e6d69ea0SShihong Wang 		.action = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL,
316e6d69ea0SShihong Wang 		.protocol = RTE_SECURITY_PROTOCOL_IPSEC,
317e6d69ea0SShihong Wang 		.ipsec = {
318e6d69ea0SShihong Wang 			.mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL,
319e6d69ea0SShihong Wang 			.direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS,
320e6d69ea0SShihong Wang 			.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
321e6d69ea0SShihong Wang 			.options = {
322e6d69ea0SShihong Wang 				.udp_encap = 1,
323e6d69ea0SShihong Wang 				.stats = 1,
324e6d69ea0SShihong Wang 				.esn = 1
325e6d69ea0SShihong Wang 				}
326e6d69ea0SShihong Wang 		},
32768287e9bSShihong Wang 		.crypto_capabilities = nfp_crypto_caps
328e6d69ea0SShihong Wang 	},
329e6d69ea0SShihong Wang 	{ /* IPsec Inline Protocol Transport Egress */
330e6d69ea0SShihong Wang 		.action = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL,
331e6d69ea0SShihong Wang 		.protocol = RTE_SECURITY_PROTOCOL_IPSEC,
332e6d69ea0SShihong Wang 		.ipsec = {
333e6d69ea0SShihong Wang 			.mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
334e6d69ea0SShihong Wang 			.direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS,
335e6d69ea0SShihong Wang 			.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
336e6d69ea0SShihong Wang 			.options = {
337e6d69ea0SShihong Wang 				.udp_encap = 1,
338e6d69ea0SShihong Wang 				.stats = 1,
339e6d69ea0SShihong Wang 				.esn = 1
340e6d69ea0SShihong Wang 				}
341e6d69ea0SShihong Wang 		},
34268287e9bSShihong Wang 		.crypto_capabilities = nfp_crypto_caps,
34368287e9bSShihong Wang 		.ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA
344e6d69ea0SShihong Wang 	},
345e6d69ea0SShihong Wang 	{ /* IPsec Inline Protocol Transport Ingress */
346e6d69ea0SShihong Wang 		.action = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL,
347e6d69ea0SShihong Wang 		.protocol = RTE_SECURITY_PROTOCOL_IPSEC,
348e6d69ea0SShihong Wang 		.ipsec = {
349e6d69ea0SShihong Wang 			.mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
350e6d69ea0SShihong Wang 			.direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS,
351e6d69ea0SShihong Wang 			.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
352e6d69ea0SShihong Wang 			.options = {
353e6d69ea0SShihong Wang 				.udp_encap = 1,
354e6d69ea0SShihong Wang 				.stats = 1,
355e6d69ea0SShihong Wang 				.esn = 1
356e6d69ea0SShihong Wang 				}
357e6d69ea0SShihong Wang 		},
35868287e9bSShihong Wang 		.crypto_capabilities = nfp_crypto_caps
359e6d69ea0SShihong Wang 	},
360e6d69ea0SShihong Wang 	{
361e6d69ea0SShihong Wang 		.action = RTE_SECURITY_ACTION_TYPE_NONE
362e6d69ea0SShihong Wang 	}
363e6d69ea0SShihong Wang };
364e6d69ea0SShihong Wang 
3657fb333e9SShihong Wang /* IPsec config message cmd codes */
3667fb333e9SShihong Wang enum nfp_ipsec_cfg_msg_cmd_codes {
3677fb333e9SShihong Wang 	NFP_IPSEC_CFG_MSG_ADD_SA,       /**< Add a new SA */
3687fb333e9SShihong Wang 	NFP_IPSEC_CFG_MSG_INV_SA,       /**< Invalidate an existing SA */
3697fb333e9SShihong Wang 	NFP_IPSEC_CFG_MSG_MODIFY_SA,    /**< Modify an existing SA */
3707fb333e9SShihong Wang 	NFP_IPSEC_CFG_MSG_GET_SA_STATS, /**< Report SA counters, flags, etc. */
3717fb333e9SShihong Wang 	NFP_IPSEC_CFG_MSG_GET_SEQ_NUMS, /**< Allocate sequence numbers */
3727fb333e9SShihong Wang 	NFP_IPSEC_CFG_MSG_LAST
3737fb333e9SShihong Wang };
3747fb333e9SShihong Wang 
3757fb333e9SShihong Wang enum nfp_ipsec_cfg_msg_rsp_codes {
3767fb333e9SShihong Wang 	NFP_IPSEC_CFG_MSG_OK,
3777fb333e9SShihong Wang 	NFP_IPSEC_CFG_MSG_FAILED,
3787fb333e9SShihong Wang 	NFP_IPSEC_CFG_MSG_SA_VALID,
3797fb333e9SShihong Wang 	NFP_IPSEC_CFG_MSG_SA_HASH_ADD_FAILED,
3807fb333e9SShihong Wang 	NFP_IPSEC_CFG_MSG_SA_HASH_DEL_FAILED,
3817fb333e9SShihong Wang 	NFP_IPSEC_CFG_MSG_SA_INVALID_CMD
3827fb333e9SShihong Wang };
3837fb333e9SShihong Wang 
3843d21da66SChang Miao enum nfp_ipsec_mode {
3853d21da66SChang Miao 	NFP_IPSEC_MODE_TRANSPORT,
3863d21da66SChang Miao 	NFP_IPSEC_MODE_TUNNEL,
3873d21da66SChang Miao };
3883d21da66SChang Miao 
3893d21da66SChang Miao enum nfp_ipsec_protocol {
3903d21da66SChang Miao 	NFP_IPSEC_PROTOCOL_AH,
3913d21da66SChang Miao 	NFP_IPSEC_PROTOCOL_ESP,
3923d21da66SChang Miao };
3933d21da66SChang Miao 
3943d21da66SChang Miao /* Cipher modes */
3953d21da66SChang Miao enum nfp_ipsec_cimode {
3963d21da66SChang Miao 	NFP_IPSEC_CIMODE_ECB,
3973d21da66SChang Miao 	NFP_IPSEC_CIMODE_CBC,
3983d21da66SChang Miao 	NFP_IPSEC_CIMODE_CFB,
3993d21da66SChang Miao 	NFP_IPSEC_CIMODE_OFB,
4003d21da66SChang Miao 	NFP_IPSEC_CIMODE_CTR,
4013d21da66SChang Miao };
4023d21da66SChang Miao 
4033d21da66SChang Miao /* Hash types */
4043d21da66SChang Miao enum nfp_ipsec_hash_type {
4053d21da66SChang Miao 	NFP_IPSEC_HASH_NONE,
4063d21da66SChang Miao 	NFP_IPSEC_HASH_MD5_96,
4073d21da66SChang Miao 	NFP_IPSEC_HASH_SHA1_96,
4083d21da66SChang Miao 	NFP_IPSEC_HASH_SHA256_96,
4093d21da66SChang Miao 	NFP_IPSEC_HASH_SHA384_96,
4103d21da66SChang Miao 	NFP_IPSEC_HASH_SHA512_96,
4113d21da66SChang Miao 	NFP_IPSEC_HASH_MD5_128,
4123d21da66SChang Miao 	NFP_IPSEC_HASH_SHA1_80,
4133d21da66SChang Miao 	NFP_IPSEC_HASH_SHA256_128,
4143d21da66SChang Miao 	NFP_IPSEC_HASH_SHA384_192,
4153d21da66SChang Miao 	NFP_IPSEC_HASH_SHA512_256,
4163d21da66SChang Miao 	NFP_IPSEC_HASH_GF128_128,
4173d21da66SChang Miao 	NFP_IPSEC_HASH_POLY1305_128,
4183d21da66SChang Miao };
4193d21da66SChang Miao 
4203d21da66SChang Miao /* Cipher types */
4213d21da66SChang Miao enum nfp_ipsec_cipher_type {
4223d21da66SChang Miao 	NFP_IPSEC_CIPHER_NULL,
4233d21da66SChang Miao 	NFP_IPSEC_CIPHER_3DES,
4243d21da66SChang Miao 	NFP_IPSEC_CIPHER_AES128,
4253d21da66SChang Miao 	NFP_IPSEC_CIPHER_AES192,
4263d21da66SChang Miao 	NFP_IPSEC_CIPHER_AES256,
4273d21da66SChang Miao 	NFP_IPSEC_CIPHER_AES128_NULL,
4283d21da66SChang Miao 	NFP_IPSEC_CIPHER_AES192_NULL,
4293d21da66SChang Miao 	NFP_IPSEC_CIPHER_AES256_NULL,
4303d21da66SChang Miao 	NFP_IPSEC_CIPHER_CHACHA20,
4313d21da66SChang Miao };
4323d21da66SChang Miao 
4333d21da66SChang Miao /* Don't Fragment types */
4343d21da66SChang Miao enum nfp_ipsec_df_type {
4353d21da66SChang Miao 	NFP_IPSEC_DF_CLEAR,
4363d21da66SChang Miao 	NFP_IPSEC_DF_SET,
4373d21da66SChang Miao 	NFP_IPSEC_DF_COPY,
4383d21da66SChang Miao };
4393d21da66SChang Miao 
4407fb333e9SShihong Wang static int
4414a9bb682SChaoyong He nfp_ipsec_cfg_cmd_issue(struct nfp_net_hw *net_hw,
4427fb333e9SShihong Wang 		struct nfp_ipsec_msg *msg)
4437fb333e9SShihong Wang {
4447fb333e9SShihong Wang 	int ret;
4457fb333e9SShihong Wang 	uint32_t i;
4467fb333e9SShihong Wang 	uint32_t msg_size;
4477fb333e9SShihong Wang 
4487fb333e9SShihong Wang 	msg_size = RTE_DIM(msg->raw);
4497fb333e9SShihong Wang 	msg->rsp = NFP_IPSEC_CFG_MSG_OK;
4507fb333e9SShihong Wang 
4517fb333e9SShihong Wang 	for (i = 0; i < msg_size; i++)
4524a9bb682SChaoyong He 		nn_cfg_writel(&net_hw->super, NFP_NET_CFG_MBOX_VAL + 4 * i, msg->raw[i]);
4537fb333e9SShihong Wang 
4544a9bb682SChaoyong He 	ret = nfp_net_mbox_reconfig(net_hw, NFP_NET_CFG_MBOX_CMD_IPSEC);
4557fb333e9SShihong Wang 	if (ret < 0) {
456*b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Failed to IPsec reconfig mbox.");
4577fb333e9SShihong Wang 		return ret;
4587fb333e9SShihong Wang 	}
4597fb333e9SShihong Wang 
4607fb333e9SShihong Wang 	/*
4617fb333e9SShihong Wang 	 * Not all commands and callers make use of response message data. But
4627fb333e9SShihong Wang 	 * leave this up to the caller and always read and store the full
4637fb333e9SShihong Wang 	 * response. One example where the data is needed is for statistics.
4647fb333e9SShihong Wang 	 */
4657fb333e9SShihong Wang 	for (i = 0; i < msg_size; i++)
4664a9bb682SChaoyong He 		msg->raw[i] = nn_cfg_readl(&net_hw->super, NFP_NET_CFG_MBOX_VAL + 4 * i);
4677fb333e9SShihong Wang 
4687fb333e9SShihong Wang 	switch (msg->rsp) {
4697fb333e9SShihong Wang 	case NFP_IPSEC_CFG_MSG_OK:
4707fb333e9SShihong Wang 		ret = 0;
4717fb333e9SShihong Wang 		break;
4727fb333e9SShihong Wang 	case NFP_IPSEC_CFG_MSG_SA_INVALID_CMD:
4737fb333e9SShihong Wang 		ret = -EINVAL;
4747fb333e9SShihong Wang 		break;
4757fb333e9SShihong Wang 	case NFP_IPSEC_CFG_MSG_SA_VALID:
4767fb333e9SShihong Wang 		ret = -EEXIST;
4777fb333e9SShihong Wang 		break;
4787fb333e9SShihong Wang 	case NFP_IPSEC_CFG_MSG_FAILED:
4797fb333e9SShihong Wang 		/* FALLTHROUGH */
4807fb333e9SShihong Wang 	case NFP_IPSEC_CFG_MSG_SA_HASH_ADD_FAILED:
4817fb333e9SShihong Wang 		/* FALLTHROUGH */
4827fb333e9SShihong Wang 	case NFP_IPSEC_CFG_MSG_SA_HASH_DEL_FAILED:
4837fb333e9SShihong Wang 		ret = -EIO;
4847fb333e9SShihong Wang 		break;
4857fb333e9SShihong Wang 	default:
4867fb333e9SShihong Wang 		ret = -EDOM;
4877fb333e9SShihong Wang 	}
4887fb333e9SShihong Wang 
4897fb333e9SShihong Wang 	return ret;
4907fb333e9SShihong Wang }
4917fb333e9SShihong Wang 
4927fb333e9SShihong Wang /**
4933d21da66SChang Miao  * Get valid SA index from SA table
4943d21da66SChang Miao  *
4953d21da66SChang Miao  * @param data
4963d21da66SChang Miao  *   SA table pointer
4973d21da66SChang Miao  * @param sa_idx
4983d21da66SChang Miao  *   SA table index pointer
4993d21da66SChang Miao  *
5003d21da66SChang Miao  * @return
5013d21da66SChang Miao  *   Negative number on full or repeat, 0 on success
5023d21da66SChang Miao  *
5033d21da66SChang Miao  * Note: multiple sockets may create same SA session.
5043d21da66SChang Miao  */
5053d21da66SChang Miao static void
5063d21da66SChang Miao nfp_get_sa_entry(struct nfp_net_ipsec_data *data,
5073d21da66SChang Miao 		int *sa_idx)
5083d21da66SChang Miao {
5093d21da66SChang Miao 	uint32_t i;
5103d21da66SChang Miao 
5113d21da66SChang Miao 	for (i = 0; i < NFP_NET_IPSEC_MAX_SA_CNT; i++) {
5123d21da66SChang Miao 		if (data->sa_entries[i] == NULL) {
5133d21da66SChang Miao 			*sa_idx = i;
5143d21da66SChang Miao 			break;
5153d21da66SChang Miao 		}
5163d21da66SChang Miao 	}
5173d21da66SChang Miao }
5183d21da66SChang Miao 
5193d21da66SChang Miao static void
5203d21da66SChang Miao nfp_aesgcm_iv_update(struct ipsec_add_sa *cfg,
5213d21da66SChang Miao 		uint16_t iv_len,
5223d21da66SChang Miao 		const char *iv_string)
5233d21da66SChang Miao {
5243d21da66SChang Miao 	int i;
5253d21da66SChang Miao 	char *save;
5263d21da66SChang Miao 	char *iv_b;
5273d21da66SChang Miao 	char *iv_str;
5287e13f2dcSShihong Wang 	const rte_be32_t *iv_value;
52977cb4714SChaoyong He 	uint8_t cfg_iv[NFP_ESP_IV_LENGTH] = {};
5303d21da66SChang Miao 
5313d21da66SChang Miao 	iv_str = strdup(iv_string);
5324ea9eeb6SChengwen Feng 	if (iv_str == NULL) {
533*b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Failed to strdup iv_string.");
5344ea9eeb6SChengwen Feng 		return;
5354ea9eeb6SChengwen Feng 	}
5364ea9eeb6SChengwen Feng 
5373d21da66SChang Miao 	for (i = 0; i < iv_len; i++) {
5383d21da66SChang Miao 		iv_b = strtok_r(i ? NULL : iv_str, ",", &save);
5393d21da66SChang Miao 		if (iv_b == NULL)
5403d21da66SChang Miao 			break;
5413d21da66SChang Miao 
5423d21da66SChang Miao 		cfg_iv[i] = strtoul(iv_b, NULL, 0);
5433d21da66SChang Miao 	}
5443d21da66SChang Miao 
5457e13f2dcSShihong Wang 	iv_value = (const rte_be32_t *)(cfg_iv);
5467e13f2dcSShihong Wang 	cfg->aesgcm_fields.iv[0] = rte_be_to_cpu_32(iv_value[0]);
5477e13f2dcSShihong Wang 	cfg->aesgcm_fields.iv[1] = rte_be_to_cpu_32(iv_value[1]);
5483d21da66SChang Miao 
5493d21da66SChang Miao 	free(iv_str);
5503d21da66SChang Miao }
5513d21da66SChang Miao 
5523d21da66SChang Miao static int
5533d21da66SChang Miao set_aes_keylen(uint32_t key_length,
5543d21da66SChang Miao 		struct ipsec_add_sa *cfg)
5553d21da66SChang Miao {
5563d21da66SChang Miao 	switch (key_length << 3) {
5573d21da66SChang Miao 	case 128:
5583d21da66SChang Miao 		cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_AES128;
5593d21da66SChang Miao 		break;
5603d21da66SChang Miao 	case 192:
5613d21da66SChang Miao 		cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_AES192;
5623d21da66SChang Miao 		break;
5633d21da66SChang Miao 	case 256:
5643d21da66SChang Miao 		cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_AES256;
5653d21da66SChang Miao 		break;
5663d21da66SChang Miao 	default:
5673d21da66SChang Miao 		PMD_DRV_LOG(ERR, "AES cipher key length is illegal!");
5683d21da66SChang Miao 		return -EINVAL;
5693d21da66SChang Miao 	}
5703d21da66SChang Miao 
5713d21da66SChang Miao 	return 0;
5723d21da66SChang Miao }
5733d21da66SChang Miao 
5743d21da66SChang Miao /* Map rte_security_session_conf aead algo to NFP aead algo */
5753d21da66SChang Miao static int
5763d21da66SChang Miao nfp_aead_map(struct rte_eth_dev *eth_dev,
5773d21da66SChang Miao 		struct rte_crypto_aead_xform *aead,
5783d21da66SChang Miao 		uint32_t key_length,
5793d21da66SChang Miao 		struct ipsec_add_sa *cfg)
5803d21da66SChang Miao {
5813d21da66SChang Miao 	int ret;
5823d21da66SChang Miao 	uint32_t i;
5833d21da66SChang Miao 	uint32_t index;
5843d21da66SChang Miao 	uint16_t iv_len;
5853d21da66SChang Miao 	uint32_t offset;
5863d21da66SChang Miao 	uint32_t device_id;
5873d21da66SChang Miao 	const char *iv_str;
5887e13f2dcSShihong Wang 	const rte_be32_t *key;
5894a9bb682SChaoyong He 	struct nfp_net_hw *net_hw;
5903d21da66SChang Miao 
5919d723baaSChaoyong He 	net_hw = eth_dev->data->dev_private;
5924a9bb682SChaoyong He 	device_id = net_hw->device_id;
5933d21da66SChang Miao 	offset = 0;
5943d21da66SChang Miao 
5953d21da66SChang Miao 	switch (aead->algo) {
5963d21da66SChang Miao 	case RTE_CRYPTO_AEAD_AES_GCM:
5973d21da66SChang Miao 		if (aead->digest_length != 16) {
5983d21da66SChang Miao 			PMD_DRV_LOG(ERR, "ICV must be 128bit with RTE_CRYPTO_AEAD_AES_GCM!");
5993d21da66SChang Miao 			return -EINVAL;
6003d21da66SChang Miao 		}
6013d21da66SChang Miao 
6023d21da66SChang Miao 		cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CTR;
6033d21da66SChang Miao 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_GF128_128;
6043d21da66SChang Miao 
6053d21da66SChang Miao 		ret = set_aes_keylen(key_length, cfg);
6063d21da66SChang Miao 		if (ret < 0) {
6073d21da66SChang Miao 			PMD_DRV_LOG(ERR, "Failed to set AES_GCM key length!");
6083d21da66SChang Miao 			return -EINVAL;
6093d21da66SChang Miao 		}
6103d21da66SChang Miao 
6113d21da66SChang Miao 		break;
6123d21da66SChang Miao 	case RTE_CRYPTO_AEAD_CHACHA20_POLY1305:
6133d21da66SChang Miao 		if (device_id != PCI_DEVICE_ID_NFP3800_PF_NIC) {
6143d21da66SChang Miao 			PMD_DRV_LOG(ERR, "Unsupported aead CHACHA20_POLY1305 algorithm!");
6153d21da66SChang Miao 			return -EINVAL;
6163d21da66SChang Miao 		}
6173d21da66SChang Miao 
6183d21da66SChang Miao 		if (aead->digest_length != 16) {
619*b6de4353SZerun Fu 			PMD_DRV_LOG(ERR, "ICV must be 128bit with RTE_CRYPTO_AEAD_CHACHA20_POLY1305.");
6203d21da66SChang Miao 			return -EINVAL;
6213d21da66SChang Miao 		}
6223d21da66SChang Miao 
6233d21da66SChang Miao 		/* Aead->alg_key_len includes 32-bit salt */
6243d21da66SChang Miao 		if (key_length != 32) {
625*b6de4353SZerun Fu 			PMD_DRV_LOG(ERR, "Unsupported CHACHA20 key length.");
6263d21da66SChang Miao 			return -EINVAL;
6273d21da66SChang Miao 		}
6283d21da66SChang Miao 
6293d21da66SChang Miao 		/* The CHACHA20's mode is not configured */
6303d21da66SChang Miao 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_POLY1305_128;
6313d21da66SChang Miao 		cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_CHACHA20;
6323d21da66SChang Miao 		break;
6333d21da66SChang Miao 	default:
6343d21da66SChang Miao 		PMD_DRV_LOG(ERR, "Unsupported aead algorithm!");
6353d21da66SChang Miao 		return -EINVAL;
6363d21da66SChang Miao 	}
6373d21da66SChang Miao 
6387e13f2dcSShihong Wang 	key = (const rte_be32_t *)(aead->key.data);
6393d21da66SChang Miao 
6403d21da66SChang Miao 	/*
6413d21da66SChang Miao 	 * The CHACHA20's key order needs to be adjusted based on hardware design.
6423d21da66SChang Miao 	 * Unadjusted order: {K0, K1, K2, K3, K4, K5, K6, K7}
6433d21da66SChang Miao 	 * Adjusted order: {K4, K5, K6, K7, K0, K1, K2, K3}
6443d21da66SChang Miao 	 */
6453d21da66SChang Miao 	if (aead->algo == RTE_CRYPTO_AEAD_CHACHA20_POLY1305)
6463d21da66SChang Miao 		offset = key_length / sizeof(cfg->cipher_key[0]) << 1;
6473d21da66SChang Miao 
6483d21da66SChang Miao 	for (i = 0; i < key_length / sizeof(cfg->cipher_key[0]); i++) {
6493d21da66SChang Miao 		index = (i + offset) % (key_length / sizeof(cfg->cipher_key[0]));
6507e13f2dcSShihong Wang 		cfg->cipher_key[index] = rte_be_to_cpu_32(key[i]);
6513d21da66SChang Miao 	}
6523d21da66SChang Miao 
6533d21da66SChang Miao 	/*
6547e13f2dcSShihong Wang 	 * The iv of the FW is equal to ESN by default. Only the
6557e13f2dcSShihong Wang 	 * aead algorithm can offload the iv of configuration and
6567e13f2dcSShihong Wang 	 * the length of iv cannot be greater than NFP_ESP_IV_LENGTH.
6573d21da66SChang Miao 	 */
6583d21da66SChang Miao 	iv_str = getenv("ETH_SEC_IV_OVR");
6593d21da66SChang Miao 	if (iv_str != NULL) {
6603d21da66SChang Miao 		iv_len = aead->iv.length;
6617e13f2dcSShihong Wang 		if (iv_len > NFP_ESP_IV_LENGTH) {
662*b6de4353SZerun Fu 			PMD_DRV_LOG(ERR, "Unsupported length of iv data.");
6637e13f2dcSShihong Wang 			return -EINVAL;
6647e13f2dcSShihong Wang 		}
6657e13f2dcSShihong Wang 
6663d21da66SChang Miao 		nfp_aesgcm_iv_update(cfg, iv_len, iv_str);
6673d21da66SChang Miao 	}
6683d21da66SChang Miao 
6693d21da66SChang Miao 	return 0;
6703d21da66SChang Miao }
6713d21da66SChang Miao 
6723d21da66SChang Miao /* Map rte_security_session_conf cipher algo to NFP cipher algo */
6733d21da66SChang Miao static int
6743d21da66SChang Miao nfp_cipher_map(struct rte_eth_dev *eth_dev,
6753d21da66SChang Miao 		struct rte_crypto_cipher_xform *cipher,
6763d21da66SChang Miao 		uint32_t key_length,
6773d21da66SChang Miao 		struct ipsec_add_sa *cfg)
6783d21da66SChang Miao {
6793d21da66SChang Miao 	int ret;
6803d21da66SChang Miao 	uint32_t i;
6813d21da66SChang Miao 	uint32_t device_id;
6827e13f2dcSShihong Wang 	const rte_be32_t *key;
6834a9bb682SChaoyong He 	struct nfp_net_hw *net_hw;
6843d21da66SChang Miao 
6859d723baaSChaoyong He 	net_hw = eth_dev->data->dev_private;
6864a9bb682SChaoyong He 	device_id = net_hw->device_id;
6873d21da66SChang Miao 
6883d21da66SChang Miao 	switch (cipher->algo) {
6893d21da66SChang Miao 	case RTE_CRYPTO_CIPHER_NULL:
6903d21da66SChang Miao 		cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CBC;
6913d21da66SChang Miao 		cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_NULL;
6923d21da66SChang Miao 		break;
6933d21da66SChang Miao 	case RTE_CRYPTO_CIPHER_3DES_CBC:
6943d21da66SChang Miao 		if (device_id == PCI_DEVICE_ID_NFP3800_PF_NIC) {
6953d21da66SChang Miao 			PMD_DRV_LOG(ERR, "Unsupported 3DESCBC encryption algorithm!");
6963d21da66SChang Miao 			return -EINVAL;
6973d21da66SChang Miao 		}
6983d21da66SChang Miao 
6993d21da66SChang Miao 		cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CBC;
7003d21da66SChang Miao 		cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_3DES;
7013d21da66SChang Miao 		break;
7023d21da66SChang Miao 	case RTE_CRYPTO_CIPHER_AES_CBC:
7033d21da66SChang Miao 		cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CBC;
7043d21da66SChang Miao 		ret = set_aes_keylen(key_length, cfg);
7053d21da66SChang Miao 		if (ret < 0) {
7063d21da66SChang Miao 			PMD_DRV_LOG(ERR, "Failed to set cipher key length!");
7073d21da66SChang Miao 			return -EINVAL;
7083d21da66SChang Miao 		}
7093d21da66SChang Miao 
7103d21da66SChang Miao 		break;
7113d21da66SChang Miao 	default:
7123d21da66SChang Miao 		PMD_DRV_LOG(ERR, "Unsupported cipher alg!");
7133d21da66SChang Miao 		return -EINVAL;
7143d21da66SChang Miao 	}
7153d21da66SChang Miao 
7167e13f2dcSShihong Wang 	key = (const rte_be32_t *)(cipher->key.data);
7173d21da66SChang Miao 	if (key_length > sizeof(cfg->cipher_key)) {
718*b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Insufficient space for offloaded key.");
7193d21da66SChang Miao 		return -EINVAL;
7203d21da66SChang Miao 	}
7213d21da66SChang Miao 
7223d21da66SChang Miao 	for (i = 0; i < key_length / sizeof(cfg->cipher_key[0]); i++)
7237e13f2dcSShihong Wang 		cfg->cipher_key[i] = rte_be_to_cpu_32(key[i]);
7243d21da66SChang Miao 
7253d21da66SChang Miao 	return 0;
7263d21da66SChang Miao }
7273d21da66SChang Miao 
7283d21da66SChang Miao static void
7293d21da66SChang Miao set_md5hmac(struct ipsec_add_sa *cfg,
7303d21da66SChang Miao 		uint32_t *digest_length)
7313d21da66SChang Miao {
7323d21da66SChang Miao 	switch (*digest_length) {
7333d21da66SChang Miao 	case 96:
7343d21da66SChang Miao 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_MD5_96;
7353d21da66SChang Miao 		break;
7363d21da66SChang Miao 	case 128:
7373d21da66SChang Miao 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_MD5_128;
7383d21da66SChang Miao 		break;
7393d21da66SChang Miao 	default:
7403d21da66SChang Miao 		*digest_length = 0;
7413d21da66SChang Miao 	}
7423d21da66SChang Miao }
7433d21da66SChang Miao 
7443d21da66SChang Miao static void
7453d21da66SChang Miao set_sha1hmac(struct ipsec_add_sa *cfg,
7463d21da66SChang Miao 		uint32_t *digest_length)
7473d21da66SChang Miao {
7483d21da66SChang Miao 	switch (*digest_length) {
7493d21da66SChang Miao 	case 96:
7503d21da66SChang Miao 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA1_96;
7513d21da66SChang Miao 		break;
7523d21da66SChang Miao 	case 80:
7533d21da66SChang Miao 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA1_80;
7543d21da66SChang Miao 		break;
7553d21da66SChang Miao 	default:
7563d21da66SChang Miao 		*digest_length = 0;
7573d21da66SChang Miao 	}
7583d21da66SChang Miao }
7593d21da66SChang Miao 
7603d21da66SChang Miao static void
7613d21da66SChang Miao set_sha2_256hmac(struct ipsec_add_sa *cfg,
7623d21da66SChang Miao 		uint32_t *digest_length)
7633d21da66SChang Miao {
7643d21da66SChang Miao 	switch (*digest_length) {
7653d21da66SChang Miao 	case 96:
7663d21da66SChang Miao 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA256_96;
7673d21da66SChang Miao 		break;
7683d21da66SChang Miao 	case 128:
7693d21da66SChang Miao 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA256_128;
7703d21da66SChang Miao 		break;
7713d21da66SChang Miao 	default:
7723d21da66SChang Miao 		*digest_length = 0;
7733d21da66SChang Miao 	}
7743d21da66SChang Miao }
7753d21da66SChang Miao 
7763d21da66SChang Miao static void
7773d21da66SChang Miao set_sha2_384hmac(struct ipsec_add_sa *cfg,
7783d21da66SChang Miao 		uint32_t *digest_length)
7793d21da66SChang Miao {
7803d21da66SChang Miao 	switch (*digest_length) {
7813d21da66SChang Miao 	case 96:
7823d21da66SChang Miao 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA384_96;
7833d21da66SChang Miao 		break;
7843d21da66SChang Miao 	case 192:
7853d21da66SChang Miao 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA384_192;
7863d21da66SChang Miao 		break;
7873d21da66SChang Miao 	default:
7883d21da66SChang Miao 		*digest_length = 0;
7893d21da66SChang Miao 	}
7903d21da66SChang Miao }
7913d21da66SChang Miao 
7923d21da66SChang Miao static void
7933d21da66SChang Miao set_sha2_512hmac(struct ipsec_add_sa *cfg,
7943d21da66SChang Miao 		uint32_t *digest_length)
7953d21da66SChang Miao {
7963d21da66SChang Miao 	switch (*digest_length) {
7973d21da66SChang Miao 	case 96:
7983d21da66SChang Miao 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA512_96;
7993d21da66SChang Miao 		break;
8003d21da66SChang Miao 	case 256:
8013d21da66SChang Miao 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA512_256;
8023d21da66SChang Miao 		break;
8033d21da66SChang Miao 	default:
8043d21da66SChang Miao 		*digest_length = 0;
8053d21da66SChang Miao 	}
8063d21da66SChang Miao }
8073d21da66SChang Miao 
8083d21da66SChang Miao /* Map rte_security_session_conf auth algo to NFP auth algo */
8093d21da66SChang Miao static int
8103d21da66SChang Miao nfp_auth_map(struct rte_eth_dev *eth_dev,
8113d21da66SChang Miao 		struct rte_crypto_auth_xform *auth,
8123d21da66SChang Miao 		uint32_t digest_length,
8133d21da66SChang Miao 		struct ipsec_add_sa *cfg)
8143d21da66SChang Miao {
8153d21da66SChang Miao 	uint32_t i;
8163d21da66SChang Miao 	uint8_t key_length;
8173d21da66SChang Miao 	uint32_t device_id;
8187e13f2dcSShihong Wang 	const rte_be32_t *key;
8194a9bb682SChaoyong He 	struct nfp_net_hw *net_hw;
8203d21da66SChang Miao 
8213d21da66SChang Miao 	if (digest_length == 0) {
8223d21da66SChang Miao 		PMD_DRV_LOG(ERR, "Auth digest length is illegal!");
8233d21da66SChang Miao 		return -EINVAL;
8243d21da66SChang Miao 	}
8253d21da66SChang Miao 
8269d723baaSChaoyong He 	net_hw = eth_dev->data->dev_private;
8274a9bb682SChaoyong He 	device_id = net_hw->device_id;
8283d21da66SChang Miao 	digest_length = digest_length << 3;
8293d21da66SChang Miao 
8303d21da66SChang Miao 	switch (auth->algo) {
8313d21da66SChang Miao 	case RTE_CRYPTO_AUTH_NULL:
8323d21da66SChang Miao 		cfg->ctrl_word.hash = NFP_IPSEC_HASH_NONE;
8333d21da66SChang Miao 		digest_length = 1;
8343d21da66SChang Miao 		break;
8353d21da66SChang Miao 	case RTE_CRYPTO_AUTH_MD5_HMAC:
8363d21da66SChang Miao 		if (device_id == PCI_DEVICE_ID_NFP3800_PF_NIC) {
8373d21da66SChang Miao 			PMD_DRV_LOG(ERR, "Unsupported MD5HMAC authentication algorithm!");
8383d21da66SChang Miao 			return -EINVAL;
8393d21da66SChang Miao 		}
8403d21da66SChang Miao 
8413d21da66SChang Miao 		set_md5hmac(cfg, &digest_length);
8423d21da66SChang Miao 		break;
8433d21da66SChang Miao 	case RTE_CRYPTO_AUTH_SHA1_HMAC:
8443d21da66SChang Miao 		set_sha1hmac(cfg, &digest_length);
8453d21da66SChang Miao 		break;
8463d21da66SChang Miao 	case RTE_CRYPTO_AUTH_SHA256_HMAC:
8473d21da66SChang Miao 		set_sha2_256hmac(cfg, &digest_length);
8483d21da66SChang Miao 		break;
8493d21da66SChang Miao 	case RTE_CRYPTO_AUTH_SHA384_HMAC:
8503d21da66SChang Miao 		set_sha2_384hmac(cfg, &digest_length);
8513d21da66SChang Miao 		break;
8523d21da66SChang Miao 	case RTE_CRYPTO_AUTH_SHA512_HMAC:
8533d21da66SChang Miao 		set_sha2_512hmac(cfg, &digest_length);
8543d21da66SChang Miao 		break;
8553d21da66SChang Miao 	default:
8563d21da66SChang Miao 		PMD_DRV_LOG(ERR, "Unsupported auth alg!");
8573d21da66SChang Miao 		return -EINVAL;
8583d21da66SChang Miao 	}
8593d21da66SChang Miao 
8603d21da66SChang Miao 	if (digest_length == 0) {
861*b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Unsupported authentication algorithm digest length.");
8623d21da66SChang Miao 		return -EINVAL;
8633d21da66SChang Miao 	}
8643d21da66SChang Miao 
8657e13f2dcSShihong Wang 	key = (const rte_be32_t *)(auth->key.data);
8663d21da66SChang Miao 	key_length = auth->key.length;
8673d21da66SChang Miao 	if (key_length > sizeof(cfg->auth_key)) {
8683d21da66SChang Miao 		PMD_DRV_LOG(ERR, "Insufficient space for offloaded auth key!");
8693d21da66SChang Miao 		return -EINVAL;
8703d21da66SChang Miao 	}
8713d21da66SChang Miao 
8723d21da66SChang Miao 	for (i = 0; i < key_length / sizeof(cfg->auth_key[0]); i++)
8737e13f2dcSShihong Wang 		cfg->auth_key[i] = rte_be_to_cpu_32(key[i]);
8743d21da66SChang Miao 
8753d21da66SChang Miao 	return 0;
8763d21da66SChang Miao }
8773d21da66SChang Miao 
8783d21da66SChang Miao static int
8793d21da66SChang Miao nfp_crypto_msg_build(struct rte_eth_dev *eth_dev,
8803d21da66SChang Miao 		struct rte_security_session_conf *conf,
8813d21da66SChang Miao 		struct nfp_ipsec_msg *msg)
8823d21da66SChang Miao {
8833d21da66SChang Miao 	int ret;
8843d21da66SChang Miao 	struct ipsec_add_sa *cfg;
8853d21da66SChang Miao 	struct rte_crypto_sym_xform *cur;
8863d21da66SChang Miao 	struct rte_crypto_sym_xform *next;
8873d21da66SChang Miao 	enum rte_security_ipsec_sa_direction direction;
8883d21da66SChang Miao 
8893d21da66SChang Miao 	cur = conf->crypto_xform;
8903d21da66SChang Miao 	if (cur == NULL) {
8913d21da66SChang Miao 		PMD_DRV_LOG(ERR, "Unsupported crypto_xform is NULL!");
8923d21da66SChang Miao 		return -EINVAL;
8933d21da66SChang Miao 	}
8943d21da66SChang Miao 
8953d21da66SChang Miao 	next = cur->next;
8963d21da66SChang Miao 	direction = conf->ipsec.direction;
8973d21da66SChang Miao 	cfg = &msg->cfg_add_sa;
8983d21da66SChang Miao 
8993d21da66SChang Miao 	switch (cur->type) {
9003d21da66SChang Miao 	case RTE_CRYPTO_SYM_XFORM_AEAD:
9013d21da66SChang Miao 		/* Aead transforms can be used for either inbound/outbound IPsec SAs */
9023d21da66SChang Miao 		if (next != NULL) {
9033d21da66SChang Miao 			PMD_DRV_LOG(ERR, "Next crypto_xform type should be NULL!");
9043d21da66SChang Miao 			return -EINVAL;
9053d21da66SChang Miao 		}
9063d21da66SChang Miao 
9073d21da66SChang Miao 		ret = nfp_aead_map(eth_dev, &cur->aead, cur->aead.key.length, cfg);
9083d21da66SChang Miao 		if (ret < 0) {
9093d21da66SChang Miao 			PMD_DRV_LOG(ERR, "Failed to map aead alg!");
9103d21da66SChang Miao 			return ret;
9113d21da66SChang Miao 		}
9123d21da66SChang Miao 
9137e13f2dcSShihong Wang 		cfg->aesgcm_fields.salt = conf->ipsec.salt;
9143d21da66SChang Miao 		break;
9153d21da66SChang Miao 	case RTE_CRYPTO_SYM_XFORM_AUTH:
9163d21da66SChang Miao 		/* Only support Auth + Cipher for inbound */
9173d21da66SChang Miao 		if (direction != RTE_SECURITY_IPSEC_SA_DIR_INGRESS) {
9183d21da66SChang Miao 			PMD_DRV_LOG(ERR, "Direction should be INGRESS, but it is not!");
9193d21da66SChang Miao 			return -EINVAL;
9203d21da66SChang Miao 		}
9213d21da66SChang Miao 
9223d21da66SChang Miao 		if (next == NULL || next->type != RTE_CRYPTO_SYM_XFORM_CIPHER) {
9233d21da66SChang Miao 			PMD_DRV_LOG(ERR, "Next crypto_xfrm should be cipher, but it is not!");
9243d21da66SChang Miao 			return -EINVAL;
9253d21da66SChang Miao 		}
9263d21da66SChang Miao 
9273d21da66SChang Miao 		ret = nfp_auth_map(eth_dev, &cur->auth, cur->auth.digest_length, cfg);
9283d21da66SChang Miao 		if (ret < 0) {
9293d21da66SChang Miao 			PMD_DRV_LOG(ERR, "Failed to map auth alg!");
9303d21da66SChang Miao 			return ret;
9313d21da66SChang Miao 		}
9323d21da66SChang Miao 
9333d21da66SChang Miao 		ret = nfp_cipher_map(eth_dev, &next->cipher, next->cipher.key.length, cfg);
9343d21da66SChang Miao 		if (ret < 0) {
9353d21da66SChang Miao 			PMD_DRV_LOG(ERR, "Failed to map cipher alg!");
9363d21da66SChang Miao 			return ret;
9373d21da66SChang Miao 		}
9383d21da66SChang Miao 
9393d21da66SChang Miao 		break;
9403d21da66SChang Miao 	case RTE_CRYPTO_SYM_XFORM_CIPHER:
9413d21da66SChang Miao 		/* Only support Cipher + Auth for outbound */
9423d21da66SChang Miao 		if (direction != RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
9433d21da66SChang Miao 			PMD_DRV_LOG(ERR, "Direction should be EGRESS, but it is not!");
9443d21da66SChang Miao 			return -EINVAL;
9453d21da66SChang Miao 		}
9463d21da66SChang Miao 
9473d21da66SChang Miao 		if (next == NULL || next->type != RTE_CRYPTO_SYM_XFORM_AUTH) {
9483d21da66SChang Miao 			PMD_DRV_LOG(ERR, "Next crypto_xfrm should be auth, but it is not!");
9493d21da66SChang Miao 			return -EINVAL;
9503d21da66SChang Miao 		}
9513d21da66SChang Miao 
9523d21da66SChang Miao 		ret = nfp_cipher_map(eth_dev, &cur->cipher, cur->cipher.key.length, cfg);
9533d21da66SChang Miao 		if (ret < 0) {
9543d21da66SChang Miao 			PMD_DRV_LOG(ERR, "Failed to map cipher alg!");
9553d21da66SChang Miao 			return ret;
9563d21da66SChang Miao 		}
9573d21da66SChang Miao 
9583d21da66SChang Miao 		ret = nfp_auth_map(eth_dev, &next->auth, next->auth.digest_length, cfg);
9593d21da66SChang Miao 		if (ret < 0) {
9603d21da66SChang Miao 			PMD_DRV_LOG(ERR, "Failed to map auth alg!");
9613d21da66SChang Miao 			return ret;
9623d21da66SChang Miao 		}
9633d21da66SChang Miao 
9643d21da66SChang Miao 		break;
9653d21da66SChang Miao 	default:
9663d21da66SChang Miao 		PMD_DRV_LOG(ERR, "Unsupported crypto_xform type!");
9673d21da66SChang Miao 		return -EINVAL;
9683d21da66SChang Miao 	}
9693d21da66SChang Miao 
9703d21da66SChang Miao 	return 0;
9713d21da66SChang Miao }
9723d21da66SChang Miao 
9733d21da66SChang Miao static int
9743d21da66SChang Miao nfp_ipsec_msg_build(struct rte_eth_dev *eth_dev,
9753d21da66SChang Miao 		struct rte_security_session_conf *conf,
9763d21da66SChang Miao 		struct nfp_ipsec_msg *msg)
9773d21da66SChang Miao {
9787e13f2dcSShihong Wang 	int i;
9793d21da66SChang Miao 	int ret;
9807e13f2dcSShihong Wang 	rte_be32_t *src_ip;
9817e13f2dcSShihong Wang 	rte_be32_t *dst_ip;
9823d21da66SChang Miao 	struct ipsec_add_sa *cfg;
9833d21da66SChang Miao 	enum rte_security_ipsec_tunnel_type type;
9843d21da66SChang Miao 
9853d21da66SChang Miao 	cfg = &msg->cfg_add_sa;
9863d21da66SChang Miao 	cfg->spi = conf->ipsec.spi;
9873d21da66SChang Miao 	cfg->pmtu_limit = 0xffff;
9883d21da66SChang Miao 
9893d21da66SChang Miao 	/*
9903d21da66SChang Miao 	 * UDP encapsulation
9913d21da66SChang Miao 	 *
9923d21da66SChang Miao 	 * 1: Do UDP encapsulation/decapsulation
9933d21da66SChang Miao 	 * 0: No UDP encapsulation
9943d21da66SChang Miao 	 */
9953d21da66SChang Miao 	if (conf->ipsec.options.udp_encap == 1) {
9963d21da66SChang Miao 		cfg->udp_enable = 1;
9973d21da66SChang Miao 		cfg->natt_dst_port = NFP_UDP_ESP_PORT;
9983d21da66SChang Miao 		cfg->natt_src_port = NFP_UDP_ESP_PORT;
9993d21da66SChang Miao 	}
10003d21da66SChang Miao 
10013d21da66SChang Miao 	if (conf->ipsec.options.copy_df == 1)
10023d21da66SChang Miao 		cfg->df_ctrl = NFP_IPSEC_DF_COPY;
10033d21da66SChang Miao 	else if (conf->ipsec.tunnel.ipv4.df != 0)
10043d21da66SChang Miao 		cfg->df_ctrl = NFP_IPSEC_DF_SET;
10053d21da66SChang Miao 	else
10063d21da66SChang Miao 		cfg->df_ctrl = NFP_IPSEC_DF_CLEAR;
10073d21da66SChang Miao 
10083d21da66SChang Miao 	switch (conf->action_type) {
10093d21da66SChang Miao 	case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO:
10103d21da66SChang Miao 		cfg->ctrl_word.encap_dsbl = 1;
10113d21da66SChang Miao 		break;
10123d21da66SChang Miao 	case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL:
10133d21da66SChang Miao 		cfg->ctrl_word.encap_dsbl = 0;
10143d21da66SChang Miao 		break;
10153d21da66SChang Miao 	default:
1016*b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Unsupported IPsec action for offload, action: %d.",
10173d21da66SChang Miao 				conf->action_type);
10183d21da66SChang Miao 		return -EINVAL;
10193d21da66SChang Miao 	}
10203d21da66SChang Miao 
10213d21da66SChang Miao 	switch (conf->ipsec.proto) {
10223d21da66SChang Miao 	case RTE_SECURITY_IPSEC_SA_PROTO_ESP:
10233d21da66SChang Miao 		cfg->ctrl_word.proto = NFP_IPSEC_PROTOCOL_ESP;
10243d21da66SChang Miao 		break;
10253d21da66SChang Miao 	case RTE_SECURITY_IPSEC_SA_PROTO_AH:
10263d21da66SChang Miao 		cfg->ctrl_word.proto = NFP_IPSEC_PROTOCOL_AH;
10273d21da66SChang Miao 		break;
10283d21da66SChang Miao 	default:
1029*b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Unsupported IPsec protocol for offload, protocol: %d.",
10303d21da66SChang Miao 				conf->ipsec.proto);
10313d21da66SChang Miao 		return -EINVAL;
10323d21da66SChang Miao 	}
10333d21da66SChang Miao 
10343d21da66SChang Miao 	switch (conf->ipsec.mode) {
10353d21da66SChang Miao 	case RTE_SECURITY_IPSEC_SA_MODE_TUNNEL:
10363d21da66SChang Miao 		type = conf->ipsec.tunnel.type;
10373d21da66SChang Miao 		cfg->ctrl_word.mode = NFP_IPSEC_MODE_TUNNEL;
10383d21da66SChang Miao 		if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV4) {
10397e13f2dcSShihong Wang 			src_ip = (rte_be32_t *)&conf->ipsec.tunnel.ipv4.src_ip.s_addr;
10407e13f2dcSShihong Wang 			dst_ip = (rte_be32_t *)&conf->ipsec.tunnel.ipv4.dst_ip.s_addr;
10417e13f2dcSShihong Wang 			cfg->src_ip[0] = rte_be_to_cpu_32(src_ip[0]);
10427e13f2dcSShihong Wang 			cfg->dst_ip[0] = rte_be_to_cpu_32(dst_ip[0]);
10433d21da66SChang Miao 			cfg->ipv6 = 0;
10443d21da66SChang Miao 		} else if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV6) {
10452ede1422SRobin Jarry 			src_ip = (rte_be32_t *)&conf->ipsec.tunnel.ipv6.src_addr;
10462ede1422SRobin Jarry 			dst_ip = (rte_be32_t *)&conf->ipsec.tunnel.ipv6.dst_addr;
10477e13f2dcSShihong Wang 			for (i = 0; i < 4; i++) {
10487e13f2dcSShihong Wang 				cfg->src_ip[i] = rte_be_to_cpu_32(src_ip[i]);
10497e13f2dcSShihong Wang 				cfg->dst_ip[i] = rte_be_to_cpu_32(dst_ip[i]);
10507e13f2dcSShihong Wang 			}
10513d21da66SChang Miao 			cfg->ipv6 = 1;
10523d21da66SChang Miao 		} else {
10533d21da66SChang Miao 			PMD_DRV_LOG(ERR, "Unsupported address family!");
10543d21da66SChang Miao 			return -EINVAL;
10553d21da66SChang Miao 		}
10563d21da66SChang Miao 
10573d21da66SChang Miao 		break;
10583d21da66SChang Miao 	case RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT:
10593d21da66SChang Miao 		cfg->ctrl_word.mode = NFP_IPSEC_MODE_TRANSPORT;
10603d21da66SChang Miao 		memset(&cfg->src_ip, 0, sizeof(cfg->src_ip));
10617e13f2dcSShihong Wang 		memset(&cfg->dst_ip, 0, sizeof(cfg->dst_ip));
10623d21da66SChang Miao 
10633d21da66SChang Miao 		break;
10643d21da66SChang Miao 	default:
1065*b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Unsupported IPsec mode for offload, mode: %d.",
10663d21da66SChang Miao 				conf->ipsec.mode);
10673d21da66SChang Miao 		return -EINVAL;
10683d21da66SChang Miao 	}
10693d21da66SChang Miao 
10703d21da66SChang Miao 	ret = nfp_crypto_msg_build(eth_dev, conf, msg);
10713d21da66SChang Miao 	if (ret < 0) {
10723d21da66SChang Miao 		PMD_DRV_LOG(ERR, "Failed to build auth/crypto/aead msg!");
10733d21da66SChang Miao 		return ret;
10743d21da66SChang Miao 	}
10753d21da66SChang Miao 
10763d21da66SChang Miao 	return 0;
10773d21da66SChang Miao }
10783d21da66SChang Miao 
10793d21da66SChang Miao static int
10803d21da66SChang Miao nfp_crypto_create_session(void *device,
10813d21da66SChang Miao 		struct rte_security_session_conf *conf,
10823d21da66SChang Miao 		struct rte_security_session *session)
10833d21da66SChang Miao {
10843d21da66SChang Miao 	int ret;
10853d21da66SChang Miao 	int sa_idx;
10864a9bb682SChaoyong He 	struct nfp_net_hw *net_hw;
10873d21da66SChang Miao 	struct nfp_ipsec_msg msg;
10883d21da66SChang Miao 	struct rte_eth_dev *eth_dev;
10893d21da66SChang Miao 	struct nfp_ipsec_session *priv_session;
10903d21da66SChang Miao 
10913d21da66SChang Miao 	/* Only support IPsec at present */
10923d21da66SChang Miao 	if (conf->protocol != RTE_SECURITY_PROTOCOL_IPSEC) {
10933d21da66SChang Miao 		PMD_DRV_LOG(ERR, "Unsupported non-IPsec offload!");
10943d21da66SChang Miao 		return -EINVAL;
10953d21da66SChang Miao 	}
10963d21da66SChang Miao 
10973d21da66SChang Miao 	sa_idx = -1;
10983d21da66SChang Miao 	eth_dev = device;
10993d21da66SChang Miao 	priv_session = SECURITY_GET_SESS_PRIV(session);
11009d723baaSChaoyong He 	net_hw = eth_dev->data->dev_private;
11013d21da66SChang Miao 
11024a9bb682SChaoyong He 	if (net_hw->ipsec_data->sa_free_cnt == 0) {
1103*b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "No space in SA table, spi: %d.", conf->ipsec.spi);
11043d21da66SChang Miao 		return -EINVAL;
11053d21da66SChang Miao 	}
11063d21da66SChang Miao 
11074a9bb682SChaoyong He 	nfp_get_sa_entry(net_hw->ipsec_data, &sa_idx);
11083d21da66SChang Miao 
11093d21da66SChang Miao 	if (sa_idx < 0) {
11103d21da66SChang Miao 		PMD_DRV_LOG(ERR, "Failed to get SA entry!");
11113d21da66SChang Miao 		return -EINVAL;
11123d21da66SChang Miao 	}
11133d21da66SChang Miao 
11143d21da66SChang Miao 	memset(&msg, 0, sizeof(msg));
11153d21da66SChang Miao 	ret = nfp_ipsec_msg_build(eth_dev, conf, &msg);
11163d21da66SChang Miao 	if (ret < 0) {
11173d21da66SChang Miao 		PMD_DRV_LOG(ERR, "Failed to build IPsec msg!");
11183d21da66SChang Miao 		return -EINVAL;
11193d21da66SChang Miao 	}
11203d21da66SChang Miao 
11213d21da66SChang Miao 	msg.cmd = NFP_IPSEC_CFG_MSG_ADD_SA;
11223d21da66SChang Miao 	msg.sa_idx = sa_idx;
11234a9bb682SChaoyong He 	ret = nfp_ipsec_cfg_cmd_issue(net_hw, &msg);
11243d21da66SChang Miao 	if (ret < 0) {
1125*b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Failed to add SA to nic.");
11263d21da66SChang Miao 		return -EINVAL;
11273d21da66SChang Miao 	}
11283d21da66SChang Miao 
11293d21da66SChang Miao 	priv_session->action = conf->action_type;
11303d21da66SChang Miao 	priv_session->ipsec = conf->ipsec;
11313d21da66SChang Miao 	priv_session->msg = msg.cfg_add_sa;
11323d21da66SChang Miao 	priv_session->sa_index = sa_idx;
11333d21da66SChang Miao 	priv_session->dev = eth_dev;
11343d21da66SChang Miao 	priv_session->user_data = conf->userdata;
11353d21da66SChang Miao 
11364a9bb682SChaoyong He 	net_hw->ipsec_data->sa_free_cnt--;
11374a9bb682SChaoyong He 	net_hw->ipsec_data->sa_entries[sa_idx] = priv_session;
11383d21da66SChang Miao 
11393d21da66SChang Miao 	return 0;
11403d21da66SChang Miao }
11413d21da66SChang Miao 
11427e6c8063SShihong Wang static int
11437e6c8063SShihong Wang nfp_crypto_update_session(void *device __rte_unused,
11447e6c8063SShihong Wang 		struct rte_security_session *session,
11457e6c8063SShihong Wang 		struct rte_security_session_conf *conf)
11467e6c8063SShihong Wang {
11477e6c8063SShihong Wang 	struct nfp_ipsec_session *priv_session;
11487e6c8063SShihong Wang 
11497e6c8063SShihong Wang 	priv_session = SECURITY_GET_SESS_PRIV(session);
11507e6c8063SShihong Wang 	if (priv_session == NULL)
11517e6c8063SShihong Wang 		return -EINVAL;
11527e6c8063SShihong Wang 
11537e6c8063SShihong Wang 	/* Update IPsec ESN value */
11547e6c8063SShihong Wang 	if (priv_session->msg.ctrl_word.ext_seq != 0 && conf->ipsec.options.esn != 0) {
11557e6c8063SShihong Wang 		/*
11567e6c8063SShihong Wang 		 * Store in nfp_ipsec_session for outbound SA for use
11577e6c8063SShihong Wang 		 * in nfp_security_set_pkt_metadata() function.
11587e6c8063SShihong Wang 		 */
11597e6c8063SShihong Wang 		priv_session->ipsec.esn.hi = conf->ipsec.esn.hi;
11607e6c8063SShihong Wang 		priv_session->ipsec.esn.low = conf->ipsec.esn.low;
11617e6c8063SShihong Wang 	}
11627e6c8063SShihong Wang 
11637e6c8063SShihong Wang 	return 0;
11647e6c8063SShihong Wang }
11657e6c8063SShihong Wang 
1166310a1780SShihong Wang static int
1167310a1780SShihong Wang nfp_security_set_pkt_metadata(void *device,
1168310a1780SShihong Wang 		struct rte_security_session *session,
1169310a1780SShihong Wang 		struct rte_mbuf *m,
1170310a1780SShihong Wang 		void *params)
1171310a1780SShihong Wang {
1172310a1780SShihong Wang 	int offset;
1173310a1780SShihong Wang 	uint64_t *sqn;
11744a9bb682SChaoyong He 	struct nfp_net_hw *net_hw;
1175310a1780SShihong Wang 	struct rte_eth_dev *eth_dev;
1176310a1780SShihong Wang 	struct nfp_ipsec_session *priv_session;
1177310a1780SShihong Wang 
1178310a1780SShihong Wang 	sqn = params;
1179310a1780SShihong Wang 	eth_dev = device;
1180310a1780SShihong Wang 	priv_session = SECURITY_GET_SESS_PRIV(session);
11819d723baaSChaoyong He 	net_hw = eth_dev->data->dev_private;
1182310a1780SShihong Wang 
1183310a1780SShihong Wang 	if (priv_session->ipsec.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
1184310a1780SShihong Wang 		struct nfp_tx_ipsec_desc_msg *desc_md;
1185310a1780SShihong Wang 
11864a9bb682SChaoyong He 		offset = net_hw->ipsec_data->pkt_dynfield_offset;
1187310a1780SShihong Wang 		desc_md = RTE_MBUF_DYNFIELD(m, offset, struct nfp_tx_ipsec_desc_msg *);
1188310a1780SShihong Wang 
1189310a1780SShihong Wang 		if (priv_session->msg.ctrl_word.ext_seq != 0 && sqn != NULL) {
11907e13f2dcSShihong Wang 			desc_md->esn.low = (uint32_t)*sqn;
11917e13f2dcSShihong Wang 			desc_md->esn.hi = (uint32_t)(*sqn >> 32);
1192310a1780SShihong Wang 		} else if (priv_session->msg.ctrl_word.ext_seq != 0) {
11937e13f2dcSShihong Wang 			desc_md->esn.low = priv_session->ipsec.esn.low;
11947e13f2dcSShihong Wang 			desc_md->esn.hi = priv_session->ipsec.esn.hi;
1195310a1780SShihong Wang 		} else {
11967e13f2dcSShihong Wang 			desc_md->esn.low = priv_session->ipsec.esn.low;
1197310a1780SShihong Wang 			desc_md->esn.hi = 0;
1198310a1780SShihong Wang 		}
1199310a1780SShihong Wang 
1200310a1780SShihong Wang 		desc_md->enc = 1;
12017e13f2dcSShihong Wang 		desc_md->sa_idx = priv_session->sa_index;
1202310a1780SShihong Wang 	}
1203310a1780SShihong Wang 
1204310a1780SShihong Wang 	return 0;
1205310a1780SShihong Wang }
1206310a1780SShihong Wang 
12073d21da66SChang Miao /**
12087fb333e9SShihong Wang  * Get discards packet statistics for each SA
12097fb333e9SShihong Wang  *
12107fb333e9SShihong Wang  * The sa_discard_stats contains the statistics of discards packets
12117fb333e9SShihong Wang  * of an SA. This function calculates the sum total of discarded packets.
12127fb333e9SShihong Wang  *
12137fb333e9SShihong Wang  * @param errors
12147fb333e9SShihong Wang  *   The value is SA discards packet sum total
12157fb333e9SShihong Wang  * @param sa_discard_stats
12167fb333e9SShihong Wang  *   The struct is SA discards packet Statistics
12177fb333e9SShihong Wang  */
12187fb333e9SShihong Wang static void
12197fb333e9SShihong Wang nfp_get_errorstats(uint64_t *errors,
12207fb333e9SShihong Wang 		struct ipsec_discard_stats *sa_discard_stats)
12217fb333e9SShihong Wang {
12227fb333e9SShihong Wang 	uint32_t i;
12237fb333e9SShihong Wang 	uint32_t len;
12247fb333e9SShihong Wang 	uint32_t *perror;
12257fb333e9SShihong Wang 
12267fb333e9SShihong Wang 	perror = &sa_discard_stats->discards_auth;
12277fb333e9SShihong Wang 	len = sizeof(struct ipsec_discard_stats) / sizeof(uint32_t);
12287fb333e9SShihong Wang 
12297fb333e9SShihong Wang 	for (i = 0; i < len; i++)
12307fb333e9SShihong Wang 		*errors += *perror++;
12317fb333e9SShihong Wang 
12327fb333e9SShihong Wang 	*errors -= sa_discard_stats->ipv4_id_counter;
12337fb333e9SShihong Wang }
12347fb333e9SShihong Wang 
12357fb333e9SShihong Wang static int
12367fb333e9SShihong Wang nfp_security_session_get_stats(void *device,
12377fb333e9SShihong Wang 		struct rte_security_session *session,
12387fb333e9SShihong Wang 		struct rte_security_stats *stats)
12397fb333e9SShihong Wang {
12407fb333e9SShihong Wang 	int ret;
12414a9bb682SChaoyong He 	struct nfp_net_hw *net_hw;
12427fb333e9SShihong Wang 	struct nfp_ipsec_msg msg;
12437fb333e9SShihong Wang 	struct rte_eth_dev *eth_dev;
12447fb333e9SShihong Wang 	struct ipsec_get_sa_stats *cfg_s;
12457fb333e9SShihong Wang 	struct rte_security_ipsec_stats *ips_s;
12467fb333e9SShihong Wang 	struct nfp_ipsec_session *priv_session;
12477fb333e9SShihong Wang 	enum rte_security_ipsec_sa_direction direction;
12487fb333e9SShihong Wang 
12497fb333e9SShihong Wang 	eth_dev = device;
12507fb333e9SShihong Wang 	priv_session = SECURITY_GET_SESS_PRIV(session);
12517fb333e9SShihong Wang 	memset(&msg, 0, sizeof(msg));
12527fb333e9SShihong Wang 	msg.cmd = NFP_IPSEC_CFG_MSG_GET_SA_STATS;
12537fb333e9SShihong Wang 	msg.sa_idx = priv_session->sa_index;
12549d723baaSChaoyong He 	net_hw = eth_dev->data->dev_private;
12557fb333e9SShihong Wang 
12564a9bb682SChaoyong He 	ret = nfp_ipsec_cfg_cmd_issue(net_hw, &msg);
12577fb333e9SShihong Wang 	if (ret < 0) {
1258*b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Failed to get SA stats.");
12597fb333e9SShihong Wang 		return ret;
12607fb333e9SShihong Wang 	}
12617fb333e9SShihong Wang 
12627fb333e9SShihong Wang 	cfg_s = &msg.cfg_get_stats;
12637fb333e9SShihong Wang 	direction = priv_session->ipsec.direction;
12647fb333e9SShihong Wang 	memset(stats, 0, sizeof(struct rte_security_stats)); /* Start with zeros */
12657fb333e9SShihong Wang 	stats->protocol = RTE_SECURITY_PROTOCOL_IPSEC;
12667fb333e9SShihong Wang 	ips_s = &stats->ipsec;
12677fb333e9SShihong Wang 
12687fb333e9SShihong Wang 	/* Only display SA if any counters are non-zero */
12697fb333e9SShihong Wang 	if (cfg_s->lifetime_byte_count != 0 || cfg_s->pkt_count != 0) {
12707fb333e9SShihong Wang 		if (direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) {
12717fb333e9SShihong Wang 			ips_s->ipackets = cfg_s->pkt_count;
12727fb333e9SShihong Wang 			ips_s->ibytes = cfg_s->lifetime_byte_count;
12737fb333e9SShihong Wang 			nfp_get_errorstats(&ips_s->ierrors, &cfg_s->sa_discard_stats);
12747fb333e9SShihong Wang 		} else {
12757fb333e9SShihong Wang 			ips_s->opackets = cfg_s->pkt_count;
12767fb333e9SShihong Wang 			ips_s->obytes = cfg_s->lifetime_byte_count;
12777fb333e9SShihong Wang 			nfp_get_errorstats(&ips_s->oerrors, &cfg_s->sa_discard_stats);
12787fb333e9SShihong Wang 		}
12797fb333e9SShihong Wang 	}
12807fb333e9SShihong Wang 
12817fb333e9SShihong Wang 	return 0;
12827fb333e9SShihong Wang }
12837fb333e9SShihong Wang 
1284e6d69ea0SShihong Wang static const struct rte_security_capability *
1285e6d69ea0SShihong Wang nfp_crypto_capabilities_get(void *device __rte_unused)
1286e6d69ea0SShihong Wang {
1287e6d69ea0SShihong Wang 	return nfp_security_caps;
1288e6d69ea0SShihong Wang }
1289e6d69ea0SShihong Wang 
1290e6d69ea0SShihong Wang static uint32_t
1291e6d69ea0SShihong Wang nfp_security_session_get_size(void *device __rte_unused)
1292e6d69ea0SShihong Wang {
1293e6d69ea0SShihong Wang 	return sizeof(struct nfp_ipsec_session);
1294e6d69ea0SShihong Wang }
1295e6d69ea0SShihong Wang 
1296eaf38c9bSShihong Wang static int
1297eaf38c9bSShihong Wang nfp_crypto_remove_sa(struct rte_eth_dev *eth_dev,
1298eaf38c9bSShihong Wang 		struct nfp_ipsec_session *priv_session)
1299eaf38c9bSShihong Wang {
1300eaf38c9bSShihong Wang 	int ret;
1301eaf38c9bSShihong Wang 	uint32_t sa_index;
13024a9bb682SChaoyong He 	struct nfp_net_hw *net_hw;
1303eaf38c9bSShihong Wang 	struct nfp_ipsec_msg cfg;
1304eaf38c9bSShihong Wang 
1305eaf38c9bSShihong Wang 	sa_index = priv_session->sa_index;
13069d723baaSChaoyong He 	net_hw = eth_dev->data->dev_private;
1307eaf38c9bSShihong Wang 
1308eaf38c9bSShihong Wang 	cfg.cmd = NFP_IPSEC_CFG_MSG_INV_SA;
1309eaf38c9bSShihong Wang 	cfg.sa_idx = sa_index;
13104a9bb682SChaoyong He 	ret = nfp_ipsec_cfg_cmd_issue(net_hw, &cfg);
1311eaf38c9bSShihong Wang 	if (ret < 0) {
1312eaf38c9bSShihong Wang 		PMD_DRV_LOG(ERR, "Failed to remove SA!");
1313eaf38c9bSShihong Wang 		return -EINVAL;
1314eaf38c9bSShihong Wang 	}
1315eaf38c9bSShihong Wang 
13164a9bb682SChaoyong He 	net_hw->ipsec_data->sa_free_cnt++;
13174a9bb682SChaoyong He 	net_hw->ipsec_data->sa_entries[sa_index] = NULL;
1318eaf38c9bSShihong Wang 
1319eaf38c9bSShihong Wang 	return 0;
1320eaf38c9bSShihong Wang }
1321eaf38c9bSShihong Wang 
1322eaf38c9bSShihong Wang static int
1323eaf38c9bSShihong Wang nfp_crypto_remove_session(void *device,
1324eaf38c9bSShihong Wang 		struct rte_security_session *session)
1325eaf38c9bSShihong Wang {
1326eaf38c9bSShihong Wang 	int ret;
1327eaf38c9bSShihong Wang 	struct rte_eth_dev *eth_dev;
1328eaf38c9bSShihong Wang 	struct nfp_ipsec_session *priv_session;
1329eaf38c9bSShihong Wang 
1330eaf38c9bSShihong Wang 	eth_dev = device;
1331eaf38c9bSShihong Wang 	priv_session = SECURITY_GET_SESS_PRIV(session);
1332eaf38c9bSShihong Wang 	if (eth_dev != priv_session->dev) {
1333*b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Session not bound to this device.");
1334eaf38c9bSShihong Wang 		return -ENODEV;
1335eaf38c9bSShihong Wang 	}
1336eaf38c9bSShihong Wang 
1337eaf38c9bSShihong Wang 	ret = nfp_crypto_remove_sa(eth_dev, priv_session);
1338eaf38c9bSShihong Wang 	if (ret < 0) {
1339*b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Failed to remove session.");
1340eaf38c9bSShihong Wang 		return -EFAULT;
1341eaf38c9bSShihong Wang 	}
1342eaf38c9bSShihong Wang 
1343eaf38c9bSShihong Wang 	memset(priv_session, 0, sizeof(struct nfp_ipsec_session));
1344eaf38c9bSShihong Wang 
1345eaf38c9bSShihong Wang 	return 0;
1346eaf38c9bSShihong Wang }
1347eaf38c9bSShihong Wang 
1348e6d69ea0SShihong Wang static const struct rte_security_ops nfp_security_ops = {
13493d21da66SChang Miao 	.session_create = nfp_crypto_create_session,
13507e6c8063SShihong Wang 	.session_update = nfp_crypto_update_session,
1351e6d69ea0SShihong Wang 	.session_get_size = nfp_security_session_get_size,
13527fb333e9SShihong Wang 	.session_stats_get = nfp_security_session_get_stats,
1353eaf38c9bSShihong Wang 	.session_destroy = nfp_crypto_remove_session,
1354310a1780SShihong Wang 	.set_pkt_metadata = nfp_security_set_pkt_metadata,
1355e6d69ea0SShihong Wang 	.capabilities_get = nfp_crypto_capabilities_get,
1356e6d69ea0SShihong Wang };
135754713740SChang Miao 
135854713740SChang Miao static int
135954713740SChang Miao nfp_ipsec_ctx_create(struct rte_eth_dev *dev,
136054713740SChang Miao 		struct nfp_net_ipsec_data *data)
136154713740SChang Miao {
136254713740SChang Miao 	struct rte_security_ctx *ctx;
136354713740SChang Miao 	static const struct rte_mbuf_dynfield pkt_md_dynfield = {
136454713740SChang Miao 		.name = "nfp_ipsec_crypto_pkt_metadata",
136554713740SChang Miao 		.size = sizeof(struct nfp_tx_ipsec_desc_msg),
136608966fe7STyler Retzlaff 		.align = alignof(struct nfp_tx_ipsec_desc_msg),
136754713740SChang Miao 	};
136854713740SChang Miao 
136954713740SChang Miao 	ctx = rte_zmalloc("security_ctx",
137054713740SChang Miao 			sizeof(struct rte_security_ctx), 0);
137154713740SChang Miao 	if (ctx == NULL) {
1372*b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Failed to malloc security_ctx.");
137354713740SChang Miao 		return -ENOMEM;
137454713740SChang Miao 	}
137554713740SChang Miao 
137654713740SChang Miao 	ctx->device = dev;
137754713740SChang Miao 	ctx->ops = &nfp_security_ops;
137854713740SChang Miao 	ctx->sess_cnt = 0;
137954713740SChang Miao 	dev->security_ctx = ctx;
138054713740SChang Miao 
138154713740SChang Miao 	data->pkt_dynfield_offset = rte_mbuf_dynfield_register(&pkt_md_dynfield);
138254713740SChang Miao 	if (data->pkt_dynfield_offset < 0) {
1383*b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Failed to register mbuf esn_dynfield.");
138454713740SChang Miao 		return -ENOMEM;
138554713740SChang Miao 	}
138654713740SChang Miao 
138754713740SChang Miao 	return 0;
138854713740SChang Miao }
138954713740SChang Miao 
139054713740SChang Miao int
139154713740SChang Miao nfp_ipsec_init(struct rte_eth_dev *dev)
139254713740SChang Miao {
139354713740SChang Miao 	int ret;
139454713740SChang Miao 	uint32_t cap_extend;
13954a9bb682SChaoyong He 	struct nfp_net_hw *net_hw;
139654713740SChang Miao 	struct nfp_net_ipsec_data *data;
139754713740SChang Miao 
13989d723baaSChaoyong He 	net_hw = dev->data->dev_private;
139954713740SChang Miao 
14004a9bb682SChaoyong He 	cap_extend = net_hw->super.cap_ext;
140154713740SChang Miao 	if ((cap_extend & NFP_NET_CFG_CTRL_IPSEC) == 0) {
1402*b6de4353SZerun Fu 		PMD_INIT_LOG(INFO, "Unsupported IPsec extend capability.");
140354713740SChang Miao 		return 0;
140454713740SChang Miao 	}
140554713740SChang Miao 
140654713740SChang Miao 	data = rte_zmalloc("ipsec_data", sizeof(struct nfp_net_ipsec_data), 0);
140754713740SChang Miao 	if (data == NULL) {
1408*b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Failed to malloc ipsec_data.");
140954713740SChang Miao 		return -ENOMEM;
141054713740SChang Miao 	}
141154713740SChang Miao 
141254713740SChang Miao 	data->pkt_dynfield_offset = -1;
141354713740SChang Miao 	data->sa_free_cnt = NFP_NET_IPSEC_MAX_SA_CNT;
14144a9bb682SChaoyong He 	net_hw->ipsec_data = data;
141554713740SChang Miao 
141654713740SChang Miao 	ret = nfp_ipsec_ctx_create(dev, data);
141754713740SChang Miao 	if (ret != 0) {
1418*b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Failed to create IPsec ctx.");
141954713740SChang Miao 		goto ipsec_cleanup;
142054713740SChang Miao 	}
142154713740SChang Miao 
142254713740SChang Miao 	return 0;
142354713740SChang Miao 
142454713740SChang Miao ipsec_cleanup:
142554713740SChang Miao 	nfp_ipsec_uninit(dev);
142654713740SChang Miao 
142754713740SChang Miao 	return ret;
142854713740SChang Miao }
142954713740SChang Miao 
143054713740SChang Miao static void
143154713740SChang Miao nfp_ipsec_ctx_destroy(struct rte_eth_dev *dev)
143254713740SChang Miao {
143354713740SChang Miao 	rte_free(dev->security_ctx);
143454713740SChang Miao }
143554713740SChang Miao 
143654713740SChang Miao void
143754713740SChang Miao nfp_ipsec_uninit(struct rte_eth_dev *dev)
143854713740SChang Miao {
143954713740SChang Miao 	uint16_t i;
144054713740SChang Miao 	uint32_t cap_extend;
14414a9bb682SChaoyong He 	struct nfp_net_hw *net_hw;
144254713740SChang Miao 	struct nfp_ipsec_session *priv_session;
144354713740SChang Miao 
14449d723baaSChaoyong He 	net_hw = dev->data->dev_private;
144554713740SChang Miao 
14464a9bb682SChaoyong He 	cap_extend = net_hw->super.cap_ext;
144754713740SChang Miao 	if ((cap_extend & NFP_NET_CFG_CTRL_IPSEC) == 0) {
1448*b6de4353SZerun Fu 		PMD_INIT_LOG(INFO, "Unsupported IPsec extend capability.");
144954713740SChang Miao 		return;
145054713740SChang Miao 	}
145154713740SChang Miao 
145254713740SChang Miao 	nfp_ipsec_ctx_destroy(dev);
145354713740SChang Miao 
14544a9bb682SChaoyong He 	if (net_hw->ipsec_data == NULL) {
145554713740SChang Miao 		PMD_INIT_LOG(INFO, "IPsec data is NULL!");
145654713740SChang Miao 		return;
145754713740SChang Miao 	}
145854713740SChang Miao 
145954713740SChang Miao 	for (i = 0; i < NFP_NET_IPSEC_MAX_SA_CNT; i++) {
14604a9bb682SChaoyong He 		priv_session = net_hw->ipsec_data->sa_entries[i];
146154713740SChang Miao 		if (priv_session != NULL)
146254713740SChang Miao 			memset(priv_session, 0, sizeof(struct nfp_ipsec_session));
146354713740SChang Miao 	}
146454713740SChang Miao 
14654a9bb682SChaoyong He 	rte_free(net_hw->ipsec_data);
146654713740SChang Miao }
146754713740SChang Miao 
1468