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