xref: /dpdk/drivers/crypto/cnxk/cn9k_ipsec.c (revision 729085b5084f9753fd9cf2e2990bbab0092f4e9d)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2021 Marvell.
3  */
4 
5 #include <cryptodev_pmd.h>
6 #include <rte_ip.h>
7 #include <rte_security.h>
8 #include <rte_security_driver.h>
9 
10 #include "cnxk_cryptodev.h"
11 #include "cnxk_cryptodev_ops.h"
12 #include "cnxk_ipsec.h"
13 #include "cnxk_security.h"
14 #include "cn9k_ipsec.h"
15 
16 #include "roc_api.h"
17 
18 static int
cn9k_ipsec_outb_sa_create(struct cnxk_cpt_qp * qp,struct rte_security_ipsec_xform * ipsec,struct rte_crypto_sym_xform * crypto_xform,struct rte_security_session * sec_sess)19 cn9k_ipsec_outb_sa_create(struct cnxk_cpt_qp *qp,
20 			  struct rte_security_ipsec_xform *ipsec,
21 			  struct rte_crypto_sym_xform *crypto_xform,
22 			  struct rte_security_session *sec_sess)
23 {
24 	struct roc_cpt *roc_cpt = qp->lf.roc_cpt;
25 	union roc_on_ipsec_outb_param1 param1;
26 	struct cnxk_cpt_inst_tmpl *inst_tmpl;
27 	struct cn9k_sec_session *sess;
28 	struct cn9k_ipsec_sa *sa;
29 	union cpt_inst_w4 w4;
30 	union cpt_inst_w7 w7;
31 	size_t ctx_len;
32 	uint8_t egrp;
33 	int ret;
34 
35 	sess = (struct cn9k_sec_session *)sec_sess;
36 	sa = &sess->sa;
37 
38 	/* Initialize lookaside IPsec private data */
39 
40 	memset(sa, 0, sizeof(struct cn9k_ipsec_sa));
41 
42 	sess->is_outbound = 1;
43 
44 	if (ipsec->esn.value)
45 		sess->esn = ipsec->esn.value - 1;
46 
47 	ret = cnxk_ipsec_outb_rlens_get(&sess->rlens, ipsec, crypto_xform);
48 	if (ret)
49 		return ret;
50 
51 	sess->custom_hdr_len =
52 		sizeof(struct roc_ie_on_outb_hdr) - ROC_IE_ON_MAX_IV_LEN;
53 
54 #ifdef LA_IPSEC_DEBUG
55 	/* Use IV from application in debug mode */
56 	if (ipsec->options.iv_gen_disable == 1) {
57 		sess->custom_hdr_len = sizeof(struct roc_ie_on_outb_hdr);
58 
59 		if (crypto_xform->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
60 			sess->cipher_iv_off = crypto_xform->aead.iv.offset;
61 			sess->cipher_iv_len = crypto_xform->aead.iv.length;
62 		} else if (crypto_xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
63 			sess->cipher_iv_off = crypto_xform->cipher.iv.offset;
64 			sess->cipher_iv_len = crypto_xform->cipher.iv.length;
65 		} else {
66 			sess->cipher_iv_off = crypto_xform->auth.iv.offset;
67 			sess->cipher_iv_len = crypto_xform->auth.iv.length;
68 		}
69 	}
70 #else
71 	if (ipsec->options.iv_gen_disable != 0) {
72 		plt_err("Application provided IV is not supported");
73 		return -ENOTSUP;
74 	}
75 #endif
76 
77 	ret = cnxk_on_ipsec_outb_sa_create(ipsec, crypto_xform, &sa->out_sa);
78 
79 	if (ret < 0)
80 		return ret;
81 
82 	ctx_len = ret;
83 	egrp = roc_cpt->eng_grp[CPT_ENG_TYPE_IE];
84 
85 	w4.u64 = 0;
86 	w4.s.opcode_major = ROC_IE_ON_MAJOR_OP_PROCESS_OUTBOUND_IPSEC | ROC_IE_ON_INPLACE_BIT;
87 	w4.s.opcode_minor = ctx_len >> 3;
88 
89 	param1.u16 = 0;
90 	param1.s.ikev2 = 1;
91 
92 #ifdef LA_IPSEC_DEBUG
93 	/* Use IV from application in debug mode */
94 	if (ipsec->options.iv_gen_disable == 1)
95 		param1.s.per_pkt_iv = ROC_IE_ON_IV_SRC_FROM_DPTR;
96 #else
97 	if (ipsec->options.iv_gen_disable != 0) {
98 		plt_err("Application provided IV is not supported");
99 		return -ENOTSUP;
100 	}
101 #endif
102 
103 	w4.s.param1 = param1.u16;
104 
105 	w7.u64 = 0;
106 	w7.s.egrp = egrp;
107 	w7.s.cptr = (uintptr_t)&sess->sa;
108 
109 	inst_tmpl = &sess->inst;
110 	inst_tmpl->w4 = w4.u64;
111 	inst_tmpl->w7 = w7.u64;
112 
113 	return 0;
114 }
115 
116 static int
cn9k_ipsec_inb_sa_create(struct cnxk_cpt_qp * qp,struct rte_security_ipsec_xform * ipsec,struct rte_crypto_sym_xform * crypto_xform,struct rte_security_session * sec_sess)117 cn9k_ipsec_inb_sa_create(struct cnxk_cpt_qp *qp,
118 			 struct rte_security_ipsec_xform *ipsec,
119 			 struct rte_crypto_sym_xform *crypto_xform,
120 			 struct rte_security_session *sec_sess)
121 {
122 	struct roc_cpt *roc_cpt = qp->lf.roc_cpt;
123 	struct cnxk_cpt_inst_tmpl *inst_tmpl;
124 	union roc_on_ipsec_inb_param2 param2;
125 	struct cn9k_sec_session *sess;
126 	struct cn9k_ipsec_sa *sa;
127 	union cpt_inst_w4 w4;
128 	union cpt_inst_w7 w7;
129 	size_t ctx_len = 0;
130 	uint8_t egrp;
131 	int ret = 0;
132 
133 	sess = (struct cn9k_sec_session *)sec_sess;
134 	sa = &sess->sa;
135 
136 	memset(sa, 0, sizeof(struct cn9k_ipsec_sa));
137 
138 	sess->is_outbound = 0;
139 	sess->replay_win_sz = ipsec->replay_win_sz;
140 
141 	if (sess->replay_win_sz) {
142 		if (sess->replay_win_sz > CNXK_ON_AR_WIN_SIZE_MAX) {
143 			plt_err("Replay window size:%u is not supported", sess->replay_win_sz);
144 			return -ENOTSUP;
145 		}
146 
147 		/* Set window bottom to 1, base and top to size of window */
148 		sess->ar.winb = 1;
149 		sess->ar.wint = sess->replay_win_sz;
150 		sess->ar.base = sess->replay_win_sz;
151 
152 		sess->seq_lo = ipsec->esn.low;
153 		sess->seq_hi = ipsec->esn.hi;
154 
155 		sess->sa.in_sa.common_sa.seq_t.tl = sess->seq_lo;
156 		sess->sa.in_sa.common_sa.seq_t.th = sess->seq_hi;
157 	}
158 
159 	ret = cnxk_on_ipsec_inb_sa_create(ipsec, crypto_xform, &sa->in_sa);
160 	if (ret < 0)
161 		return ret;
162 
163 	if (sa->in_sa.common_sa.ctl.esn_en)
164 		sess->esn_en = 1;
165 
166 	ctx_len = ret;
167 	egrp = roc_cpt->eng_grp[CPT_ENG_TYPE_IE];
168 
169 	w4.u64 = 0;
170 	w4.s.opcode_major = ROC_IE_ON_MAJOR_OP_PROCESS_INBOUND_IPSEC | ROC_IE_ON_INPLACE_BIT;
171 	w4.s.opcode_minor = ctx_len >> 3;
172 
173 	param2.u16 = 0;
174 	param2.s.ikev2 = 1;
175 	w4.s.param2 = param2.u16;
176 
177 	w7.s.egrp = egrp;
178 	w7.s.cptr = (uintptr_t)&sess->sa;
179 
180 	inst_tmpl = &sess->inst;
181 	inst_tmpl->w4 = w4.u64;
182 	inst_tmpl->w7 = w7.u64;
183 
184 	return 0;
185 }
186 
187 static inline int
cn9k_ipsec_xform_verify(struct rte_security_ipsec_xform * ipsec,struct rte_crypto_sym_xform * crypto)188 cn9k_ipsec_xform_verify(struct rte_security_ipsec_xform *ipsec,
189 			struct rte_crypto_sym_xform *crypto)
190 {
191 	if (ipsec->life.bytes_hard_limit != 0 ||
192 	    ipsec->life.bytes_soft_limit != 0 ||
193 	    ipsec->life.packets_hard_limit != 0 ||
194 	    ipsec->life.packets_soft_limit != 0)
195 		return -ENOTSUP;
196 
197 	if (ipsec->mode == RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT &&
198 	    ipsec->proto != RTE_SECURITY_IPSEC_SA_PROTO_AH) {
199 		enum rte_crypto_sym_xform_type type = crypto->type;
200 
201 		if (type == RTE_CRYPTO_SYM_XFORM_AEAD) {
202 			if ((crypto->aead.algo == RTE_CRYPTO_AEAD_AES_GCM) &&
203 			    (crypto->aead.key.length == 32)) {
204 				plt_err("Transport mode AES-256-GCM is not supported");
205 				return -ENOTSUP;
206 			}
207 		}
208 	}
209 	return 0;
210 }
211 
212 static int
cn9k_ipsec_session_create(void * dev,struct rte_security_ipsec_xform * ipsec_xform,struct rte_crypto_sym_xform * crypto_xform,struct rte_security_session * sess)213 cn9k_ipsec_session_create(void *dev,
214 			  struct rte_security_ipsec_xform *ipsec_xform,
215 			  struct rte_crypto_sym_xform *crypto_xform,
216 			  struct rte_security_session *sess)
217 {
218 	struct rte_cryptodev *crypto_dev = dev;
219 	struct cnxk_cpt_qp *qp;
220 	int ret;
221 
222 	qp = crypto_dev->data->queue_pairs[0];
223 	if (qp == NULL) {
224 		plt_err("CPT queue pairs need to be setup for creating security"
225 			" session");
226 		return -EPERM;
227 	}
228 
229 	ret = cnxk_ipsec_xform_verify(ipsec_xform, crypto_xform);
230 	if (ret)
231 		return ret;
232 
233 	ret = cn9k_ipsec_xform_verify(ipsec_xform, crypto_xform);
234 	if (ret)
235 		return ret;
236 
237 	if (ipsec_xform->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS)
238 		return cn9k_ipsec_inb_sa_create(qp, ipsec_xform, crypto_xform,
239 						sess);
240 	else
241 		return cn9k_ipsec_outb_sa_create(qp, ipsec_xform, crypto_xform,
242 						 sess);
243 }
244 
245 static int
cn9k_sec_session_create(void * device,struct rte_security_session_conf * conf,struct rte_security_session * sess)246 cn9k_sec_session_create(void *device, struct rte_security_session_conf *conf,
247 			struct rte_security_session *sess)
248 {
249 	struct cn9k_sec_session *priv = SECURITY_GET_SESS_PRIV(sess);
250 
251 	if (conf->action_type != RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL)
252 		return -EINVAL;
253 
254 	memset(priv, 0, sizeof(*priv));
255 
256 	if (conf->protocol != RTE_SECURITY_PROTOCOL_IPSEC)
257 		return -ENOTSUP;
258 
259 	return cn9k_ipsec_session_create(device, &conf->ipsec,
260 					conf->crypto_xform, sess);
261 }
262 
263 static int
cn9k_sec_session_destroy(void * device __rte_unused,struct rte_security_session * sess)264 cn9k_sec_session_destroy(void *device __rte_unused,
265 			 struct rte_security_session *sess)
266 {
267 	struct roc_ie_on_outb_sa *out_sa;
268 	struct cn9k_sec_session *priv;
269 	struct roc_ie_on_sa_ctl *ctl;
270 	struct cn9k_ipsec_sa *sa;
271 
272 	priv = SECURITY_GET_SESS_PRIV(sess);
273 	if (priv == NULL)
274 		return 0;
275 
276 	sa = &priv->sa;
277 	out_sa = &sa->out_sa;
278 
279 	ctl = &out_sa->common_sa.ctl;
280 	ctl->valid = 0;
281 
282 	rte_io_wmb();
283 
284 	memset(priv, 0, sizeof(*priv));
285 
286 	return 0;
287 }
288 
289 static unsigned int
cn9k_sec_session_get_size(void * device __rte_unused)290 cn9k_sec_session_get_size(void *device __rte_unused)
291 {
292 	return sizeof(struct cn9k_sec_session);
293 }
294 
295 static int
cn9k_sec_session_update(void * device,struct rte_security_session * sec_sess,struct rte_security_session_conf * conf)296 cn9k_sec_session_update(void *device, struct rte_security_session *sec_sess,
297 			struct rte_security_session_conf *conf)
298 {
299 	struct rte_cryptodev *crypto_dev = device;
300 	struct cnxk_cpt_qp *qp;
301 	int ret;
302 
303 	qp = crypto_dev->data->queue_pairs[0];
304 	if (qp == NULL) {
305 		plt_err("CPT queue pairs need to be setup for updating security"
306 			" session");
307 		return -EPERM;
308 	}
309 
310 	if (conf->ipsec.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS)
311 		return -ENOTSUP;
312 
313 	ret = cnxk_ipsec_xform_verify(&conf->ipsec, conf->crypto_xform);
314 	if (ret)
315 		return ret;
316 
317 	ret = cn9k_ipsec_xform_verify(&conf->ipsec, conf->crypto_xform);
318 	if (ret)
319 		return ret;
320 
321 	return cn9k_ipsec_outb_sa_create(qp, &conf->ipsec, conf->crypto_xform,
322 					 sec_sess);
323 }
324 
325 /* Update platform specific security ops */
326 void
cn9k_sec_ops_override(void)327 cn9k_sec_ops_override(void)
328 {
329 	/* Update platform specific ops */
330 	cnxk_sec_ops.session_create = cn9k_sec_session_create;
331 	cnxk_sec_ops.session_destroy = cn9k_sec_session_destroy;
332 	cnxk_sec_ops.session_get_size = cn9k_sec_session_get_size;
333 	cnxk_sec_ops.session_update = cn9k_sec_session_update;
334 }
335