98110872a334dabb9857fd639f362052afd8947e
[dpdk.git] / drivers / crypto / cnxk / cn10k_ipsec.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2021 Marvell.
3  */
4
5 #include <rte_malloc.h>
6 #include <rte_cryptodev.h>
7 #include <rte_esp.h>
8 #include <rte_ip.h>
9 #include <rte_security.h>
10 #include <rte_security_driver.h>
11 #include <rte_udp.h>
12
13 #include "cnxk_cryptodev.h"
14 #include "cnxk_ipsec.h"
15 #include "cnxk_security.h"
16 #include "cn10k_ipsec.h"
17
18 #include "roc_api.h"
19
20 static int
21 ipsec_xform_cipher_verify(struct rte_crypto_sym_xform *xform)
22 {
23         if (xform->cipher.algo == RTE_CRYPTO_CIPHER_AES_CBC) {
24                 switch (xform->cipher.key.length) {
25                 case 16:
26                 case 24:
27                 case 32:
28                         break;
29                 default:
30                         return -ENOTSUP;
31                 }
32                 return 0;
33         }
34
35         return -ENOTSUP;
36 }
37
38 static int
39 ipsec_xform_auth_verify(struct rte_crypto_sym_xform *xform)
40 {
41         uint16_t keylen = xform->auth.key.length;
42
43         if (xform->auth.algo == RTE_CRYPTO_AUTH_SHA1_HMAC) {
44                 if (keylen >= 20 && keylen <= 64)
45                         return 0;
46         }
47
48         return -ENOTSUP;
49 }
50
51 static int
52 ipsec_xform_aead_verify(struct rte_security_ipsec_xform *ipsec_xfrm,
53                         struct rte_crypto_sym_xform *crypto_xfrm)
54 {
55         if (ipsec_xfrm->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS &&
56             crypto_xfrm->aead.op != RTE_CRYPTO_AEAD_OP_ENCRYPT)
57                 return -EINVAL;
58
59         if (ipsec_xfrm->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS &&
60             crypto_xfrm->aead.op != RTE_CRYPTO_AEAD_OP_DECRYPT)
61                 return -EINVAL;
62
63         if (crypto_xfrm->aead.algo == RTE_CRYPTO_AEAD_AES_GCM) {
64                 switch (crypto_xfrm->aead.key.length) {
65                 case ROC_CPT_AES128_KEY_LEN:
66                 case ROC_CPT_AES192_KEY_LEN:
67                 case ROC_CPT_AES256_KEY_LEN:
68                         break;
69                 default:
70                         return -EINVAL;
71                 }
72                 return 0;
73         }
74
75         return -ENOTSUP;
76 }
77
78 static int
79 cn10k_ipsec_xform_verify(struct rte_security_ipsec_xform *ipsec_xfrm,
80                          struct rte_crypto_sym_xform *crypto_xfrm)
81 {
82         struct rte_crypto_sym_xform *auth_xform, *cipher_xform;
83         int ret;
84
85         if ((ipsec_xfrm->direction != RTE_SECURITY_IPSEC_SA_DIR_INGRESS) &&
86             (ipsec_xfrm->direction != RTE_SECURITY_IPSEC_SA_DIR_EGRESS))
87                 return -EINVAL;
88
89         if ((ipsec_xfrm->proto != RTE_SECURITY_IPSEC_SA_PROTO_ESP) &&
90             (ipsec_xfrm->proto != RTE_SECURITY_IPSEC_SA_PROTO_AH))
91                 return -EINVAL;
92
93         if ((ipsec_xfrm->mode != RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT) &&
94             (ipsec_xfrm->mode != RTE_SECURITY_IPSEC_SA_MODE_TUNNEL))
95                 return -EINVAL;
96
97         if ((ipsec_xfrm->tunnel.type != RTE_SECURITY_IPSEC_TUNNEL_IPV4) &&
98             (ipsec_xfrm->tunnel.type != RTE_SECURITY_IPSEC_TUNNEL_IPV6))
99                 return -EINVAL;
100
101         if (crypto_xfrm->type == RTE_CRYPTO_SYM_XFORM_AEAD)
102                 return ipsec_xform_aead_verify(ipsec_xfrm, crypto_xfrm);
103
104         if (crypto_xfrm->next == NULL)
105                 return -EINVAL;
106
107         if (ipsec_xfrm->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) {
108                 /* Ingress */
109                 if (crypto_xfrm->type != RTE_CRYPTO_SYM_XFORM_AUTH ||
110                     crypto_xfrm->next->type != RTE_CRYPTO_SYM_XFORM_CIPHER)
111                         return -EINVAL;
112                 auth_xform = crypto_xfrm;
113                 cipher_xform = crypto_xfrm->next;
114         } else {
115                 /* Egress */
116                 if (crypto_xfrm->type != RTE_CRYPTO_SYM_XFORM_CIPHER ||
117                     crypto_xfrm->next->type != RTE_CRYPTO_SYM_XFORM_AUTH)
118                         return -EINVAL;
119                 cipher_xform = crypto_xfrm;
120                 auth_xform = crypto_xfrm->next;
121         }
122
123         ret = ipsec_xform_cipher_verify(cipher_xform);
124         if (ret)
125                 return ret;
126
127         ret = ipsec_xform_auth_verify(auth_xform);
128         if (ret)
129                 return ret;
130
131         return 0;
132 }
133
134 static uint64_t
135 ipsec_cpt_inst_w7_get(struct roc_cpt *roc_cpt, void *sa)
136 {
137         union cpt_inst_w7 w7;
138
139         w7.u64 = 0;
140         w7.s.egrp = roc_cpt->eng_grp[CPT_ENG_TYPE_IE];
141         w7.s.ctx_val = 1;
142         w7.s.cptr = (uint64_t)sa;
143         rte_mb();
144
145         return w7.u64;
146 }
147
148 static int
149 cn10k_ipsec_outb_sa_create(struct roc_cpt *roc_cpt,
150                            struct rte_security_ipsec_xform *ipsec_xfrm,
151                            struct rte_crypto_sym_xform *crypto_xfrm,
152                            struct rte_security_session *sec_sess)
153 {
154         struct roc_ot_ipsec_outb_sa *out_sa;
155         struct cnxk_ipsec_outb_rlens rlens;
156         struct cn10k_sec_session *sess;
157         struct cn10k_ipsec_sa *sa;
158         union cpt_inst_w4 inst_w4;
159         int ret;
160
161         sess = get_sec_session_private_data(sec_sess);
162         sa = &sess->sa;
163         out_sa = &sa->out_sa;
164
165         memset(out_sa, 0, sizeof(struct roc_ot_ipsec_outb_sa));
166
167         /* Translate security parameters to SA */
168         ret = cnxk_ot_ipsec_outb_sa_fill(out_sa, ipsec_xfrm, crypto_xfrm);
169         if (ret)
170                 return ret;
171
172         sa->inst.w7 = ipsec_cpt_inst_w7_get(roc_cpt, sa);
173
174         /* Get Rlen calculation data */
175         ret = cnxk_ipsec_outb_rlens_get(&rlens, ipsec_xfrm, crypto_xfrm);
176         if (ret)
177                 return ret;
178
179         sa->max_extended_len = rlens.max_extended_len;
180
181         /* pre-populate CPT INST word 4 */
182         inst_w4.u64 = 0;
183         inst_w4.s.opcode_major = ROC_IE_OT_MAJOR_OP_PROCESS_OUTBOUND_IPSEC;
184         inst_w4.s.param1 = 0;
185         sa->inst.w4 = inst_w4.u64;
186
187         return 0;
188 }
189
190 static int
191 cn10k_ipsec_inb_sa_create(struct roc_cpt *roc_cpt,
192                           struct rte_security_ipsec_xform *ipsec_xfrm,
193                           struct rte_crypto_sym_xform *crypto_xfrm,
194                           struct rte_security_session *sec_sess)
195 {
196         struct roc_ot_ipsec_inb_sa *in_sa;
197         struct cn10k_sec_session *sess;
198         struct cn10k_ipsec_sa *sa;
199         union cpt_inst_w4 inst_w4;
200         int ret;
201
202         sess = get_sec_session_private_data(sec_sess);
203         sa = &sess->sa;
204         in_sa = &sa->in_sa;
205
206         /* Translate security parameters to SA */
207         ret = cnxk_ot_ipsec_inb_sa_fill(in_sa, ipsec_xfrm, crypto_xfrm);
208         if (ret)
209                 return ret;
210
211         /* TODO add support for antireplay */
212         sa->in_sa.w0.s.ar_win = 0;
213
214         /* TODO add support for udp encap */
215
216         sa->inst.w7 = ipsec_cpt_inst_w7_get(roc_cpt, sa);
217
218         /* pre-populate CPT INST word 4 */
219         inst_w4.u64 = 0;
220         inst_w4.s.opcode_major = ROC_IE_OT_MAJOR_OP_PROCESS_INBOUND_IPSEC;
221
222         /* Disable checksum verification for now */
223         inst_w4.s.param1 = 7;
224         sa->inst.w4 = inst_w4.u64;
225
226         return 0;
227 }
228
229 static int
230 cn10k_ipsec_session_create(void *dev,
231                            struct rte_security_ipsec_xform *ipsec_xfrm,
232                            struct rte_crypto_sym_xform *crypto_xfrm,
233                            struct rte_security_session *sess)
234 {
235         struct rte_cryptodev *crypto_dev = dev;
236         struct roc_cpt *roc_cpt;
237         struct cnxk_cpt_vf *vf;
238         int ret;
239
240         vf = crypto_dev->data->dev_private;
241         roc_cpt = &vf->cpt;
242
243         if (crypto_dev->data->queue_pairs[0] == NULL) {
244                 plt_err("Setup cpt queue pair before creating security session");
245                 return -EPERM;
246         }
247
248         ret = cn10k_ipsec_xform_verify(ipsec_xfrm, crypto_xfrm);
249         if (ret)
250                 return ret;
251
252         if (ipsec_xfrm->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS)
253                 return cn10k_ipsec_inb_sa_create(roc_cpt, ipsec_xfrm,
254                                                  crypto_xfrm, sess);
255         else
256                 return cn10k_ipsec_outb_sa_create(roc_cpt, ipsec_xfrm,
257                                                   crypto_xfrm, sess);
258 }
259
260 static int
261 cn10k_sec_session_create(void *device, struct rte_security_session_conf *conf,
262                          struct rte_security_session *sess,
263                          struct rte_mempool *mempool)
264 {
265         struct cn10k_sec_session *priv;
266         int ret;
267
268         if (conf->action_type != RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL)
269                 return -EINVAL;
270
271         if (rte_mempool_get(mempool, (void **)&priv)) {
272                 plt_err("Could not allocate security session private data");
273                 return -ENOMEM;
274         }
275
276         set_sec_session_private_data(sess, priv);
277
278         if (conf->protocol != RTE_SECURITY_PROTOCOL_IPSEC) {
279                 ret = -ENOTSUP;
280                 goto mempool_put;
281         }
282         ret = cn10k_ipsec_session_create(device, &conf->ipsec,
283                                          conf->crypto_xform, sess);
284         if (ret)
285                 goto mempool_put;
286
287         return 0;
288
289 mempool_put:
290         rte_mempool_put(mempool, priv);
291         set_sec_session_private_data(sess, NULL);
292         return ret;
293 }
294
295 static int
296 cn10k_sec_session_destroy(void *device __rte_unused,
297                           struct rte_security_session *sess)
298 {
299         struct cn10k_sec_session *priv;
300         struct rte_mempool *sess_mp;
301
302         priv = get_sec_session_private_data(sess);
303
304         if (priv == NULL)
305                 return 0;
306
307         sess_mp = rte_mempool_from_obj(priv);
308
309         set_sec_session_private_data(sess, NULL);
310         rte_mempool_put(sess_mp, priv);
311
312         return 0;
313 }
314
315 static unsigned int
316 cn10k_sec_session_get_size(void *device __rte_unused)
317 {
318         return sizeof(struct cn10k_sec_session);
319 }
320
321 /* Update platform specific security ops */
322 void
323 cn10k_sec_ops_override(void)
324 {
325         /* Update platform specific ops */
326         cnxk_sec_ops.session_create = cn10k_sec_session_create;
327         cnxk_sec_ops.session_destroy = cn10k_sec_session_destroy;
328         cnxk_sec_ops.session_get_size = cn10k_sec_session_get_size;
329 }