crypto/cnxk: add security session operations
[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_aead_verify(struct rte_security_ipsec_xform *ipsec_xfrm,
22                         struct rte_crypto_sym_xform *crypto_xfrm)
23 {
24         if (ipsec_xfrm->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS &&
25             crypto_xfrm->aead.op != RTE_CRYPTO_AEAD_OP_ENCRYPT)
26                 return -EINVAL;
27
28         if (ipsec_xfrm->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS &&
29             crypto_xfrm->aead.op != RTE_CRYPTO_AEAD_OP_DECRYPT)
30                 return -EINVAL;
31
32         if (crypto_xfrm->aead.algo == RTE_CRYPTO_AEAD_AES_GCM) {
33                 switch (crypto_xfrm->aead.key.length) {
34                 case ROC_CPT_AES128_KEY_LEN:
35                 case ROC_CPT_AES192_KEY_LEN:
36                 case ROC_CPT_AES256_KEY_LEN:
37                         break;
38                 default:
39                         return -EINVAL;
40                 }
41                 return 0;
42         }
43
44         return -ENOTSUP;
45 }
46
47 static int
48 cn10k_ipsec_xform_verify(struct rte_security_ipsec_xform *ipsec_xfrm,
49                          struct rte_crypto_sym_xform *crypto_xfrm)
50 {
51         if ((ipsec_xfrm->direction != RTE_SECURITY_IPSEC_SA_DIR_INGRESS) &&
52             (ipsec_xfrm->direction != RTE_SECURITY_IPSEC_SA_DIR_EGRESS))
53                 return -EINVAL;
54
55         if ((ipsec_xfrm->proto != RTE_SECURITY_IPSEC_SA_PROTO_ESP) &&
56             (ipsec_xfrm->proto != RTE_SECURITY_IPSEC_SA_PROTO_AH))
57                 return -EINVAL;
58
59         if ((ipsec_xfrm->mode != RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT) &&
60             (ipsec_xfrm->mode != RTE_SECURITY_IPSEC_SA_MODE_TUNNEL))
61                 return -EINVAL;
62
63         if ((ipsec_xfrm->tunnel.type != RTE_SECURITY_IPSEC_TUNNEL_IPV4) &&
64             (ipsec_xfrm->tunnel.type != RTE_SECURITY_IPSEC_TUNNEL_IPV6))
65                 return -EINVAL;
66
67         if (crypto_xfrm->type == RTE_CRYPTO_SYM_XFORM_AEAD)
68                 return ipsec_xform_aead_verify(ipsec_xfrm, crypto_xfrm);
69
70         return -ENOTSUP;
71 }
72
73 static uint64_t
74 ipsec_cpt_inst_w7_get(struct roc_cpt *roc_cpt, void *sa)
75 {
76         union cpt_inst_w7 w7;
77
78         w7.u64 = 0;
79         w7.s.egrp = roc_cpt->eng_grp[CPT_ENG_TYPE_IE];
80         w7.s.ctx_val = 1;
81         w7.s.cptr = (uint64_t)sa;
82         rte_mb();
83
84         return w7.u64;
85 }
86
87 static int
88 cn10k_ipsec_outb_sa_create(struct roc_cpt *roc_cpt,
89                            struct rte_security_ipsec_xform *ipsec_xfrm,
90                            struct rte_crypto_sym_xform *crypto_xfrm,
91                            struct rte_security_session *sec_sess)
92 {
93         struct roc_ot_ipsec_outb_sa *out_sa;
94         struct cnxk_ipsec_outb_rlens rlens;
95         struct cn10k_sec_session *sess;
96         struct cn10k_ipsec_sa *sa;
97         union cpt_inst_w4 inst_w4;
98         int ret;
99
100         sess = get_sec_session_private_data(sec_sess);
101         sa = &sess->sa;
102         out_sa = &sa->out_sa;
103
104         memset(out_sa, 0, sizeof(struct roc_ot_ipsec_outb_sa));
105
106         /* Translate security parameters to SA */
107         ret = cnxk_ot_ipsec_outb_sa_fill(out_sa, ipsec_xfrm, crypto_xfrm);
108         if (ret)
109                 return ret;
110
111         sa->inst.w7 = ipsec_cpt_inst_w7_get(roc_cpt, sa);
112
113         /* Get Rlen calculation data */
114         ret = cnxk_ipsec_outb_rlens_get(&rlens, ipsec_xfrm, crypto_xfrm);
115         if (ret)
116                 return ret;
117
118         sa->partial_len = rlens.partial_len;
119         sa->roundup_byte = rlens.roundup_byte;
120         sa->roundup_len = rlens.roundup_len;
121
122         /* pre-populate CPT INST word 4 */
123         inst_w4.u64 = 0;
124         inst_w4.s.opcode_major = ROC_IE_OT_MAJOR_OP_PROCESS_OUTBOUND_IPSEC;
125         inst_w4.s.param1 = 0;
126         sa->inst.w4 = inst_w4.u64;
127
128         return 0;
129 }
130
131 static int
132 cn10k_ipsec_inb_sa_create(struct roc_cpt *roc_cpt,
133                           struct rte_security_ipsec_xform *ipsec_xfrm,
134                           struct rte_crypto_sym_xform *crypto_xfrm,
135                           struct rte_security_session *sec_sess)
136 {
137         struct roc_ot_ipsec_inb_sa *in_sa;
138         struct cn10k_sec_session *sess;
139         struct cn10k_ipsec_sa *sa;
140         union cpt_inst_w4 inst_w4;
141         int ret;
142
143         sess = get_sec_session_private_data(sec_sess);
144         sa = &sess->sa;
145         in_sa = &sa->in_sa;
146
147         /* Translate security parameters to SA */
148         ret = cnxk_ot_ipsec_inb_sa_fill(in_sa, ipsec_xfrm, crypto_xfrm);
149         if (ret)
150                 return ret;
151
152         /* TODO add support for antireplay */
153         sa->in_sa.w0.s.ar_win = 0;
154
155         /* TODO add support for udp encap */
156
157         sa->inst.w7 = ipsec_cpt_inst_w7_get(roc_cpt, sa);
158
159         /* pre-populate CPT INST word 4 */
160         inst_w4.u64 = 0;
161         inst_w4.s.opcode_major = ROC_IE_OT_MAJOR_OP_PROCESS_INBOUND_IPSEC;
162
163         /* Disable checksum verification for now */
164         inst_w4.s.param1 = 7;
165         sa->inst.w4 = inst_w4.u64;
166
167         return 0;
168 }
169
170 static int
171 cn10k_ipsec_session_create(void *dev,
172                            struct rte_security_ipsec_xform *ipsec_xfrm,
173                            struct rte_crypto_sym_xform *crypto_xfrm,
174                            struct rte_security_session *sess)
175 {
176         struct rte_cryptodev *crypto_dev = dev;
177         struct roc_cpt *roc_cpt;
178         struct cnxk_cpt_vf *vf;
179         int ret;
180
181         vf = crypto_dev->data->dev_private;
182         roc_cpt = &vf->cpt;
183
184         if (crypto_dev->data->queue_pairs[0] == NULL) {
185                 plt_err("Setup cpt queue pair before creating security session");
186                 return -EPERM;
187         }
188
189         ret = cn10k_ipsec_xform_verify(ipsec_xfrm, crypto_xfrm);
190         if (ret)
191                 return ret;
192
193         if (ipsec_xfrm->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS)
194                 return cn10k_ipsec_inb_sa_create(roc_cpt, ipsec_xfrm,
195                                                  crypto_xfrm, sess);
196         else
197                 return cn10k_ipsec_outb_sa_create(roc_cpt, ipsec_xfrm,
198                                                   crypto_xfrm, sess);
199 }
200
201 static int
202 cn10k_sec_session_create(void *device, struct rte_security_session_conf *conf,
203                          struct rte_security_session *sess,
204                          struct rte_mempool *mempool)
205 {
206         struct cn10k_sec_session *priv;
207         int ret;
208
209         if (conf->action_type != RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL)
210                 return -EINVAL;
211
212         if (rte_security_dynfield_register() < 0)
213                 return -ENOTSUP;
214
215         if (rte_mempool_get(mempool, (void **)&priv)) {
216                 plt_err("Could not allocate security session private data");
217                 return -ENOMEM;
218         }
219
220         set_sec_session_private_data(sess, priv);
221
222         priv->userdata = conf->userdata;
223
224         if (conf->protocol != RTE_SECURITY_PROTOCOL_IPSEC) {
225                 ret = -ENOTSUP;
226                 goto mempool_put;
227         }
228         ret = cn10k_ipsec_session_create(device, &conf->ipsec,
229                                          conf->crypto_xform, sess);
230         if (ret)
231                 goto mempool_put;
232
233         return 0;
234
235 mempool_put:
236         rte_mempool_put(mempool, priv);
237         set_sec_session_private_data(sess, NULL);
238         return ret;
239 }
240
241 static int
242 cn10k_sec_session_destroy(void *device __rte_unused,
243                           struct rte_security_session *sess)
244 {
245         struct cn10k_sec_session *priv;
246         struct rte_mempool *sess_mp;
247
248         priv = get_sec_session_private_data(sess);
249
250         if (priv == NULL)
251                 return 0;
252
253         sess_mp = rte_mempool_from_obj(priv);
254
255         set_sec_session_private_data(sess, NULL);
256         rte_mempool_put(sess_mp, priv);
257
258         return 0;
259 }
260
261 static unsigned int
262 cn10k_sec_session_get_size(void *device __rte_unused)
263 {
264         return sizeof(struct cn10k_sec_session);
265 }
266
267 /* Update platform specific security ops */
268 void
269 cn10k_sec_ops_override(void)
270 {
271         /* Update platform specific ops */
272         cnxk_sec_ops.session_create = cn10k_sec_session_create;
273         cnxk_sec_ops.session_destroy = cn10k_sec_session_destroy;
274         cnxk_sec_ops.session_get_size = cn10k_sec_session_get_size;
275 }