common/cnxk: support UDP encapsulation
[dpdk.git] / drivers / common / cnxk / cnxk_security.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2021 Marvell.
3  */
4
5 #include <rte_udp.h>
6
7 #include "cnxk_security.h"
8
9 static int
10 ot_ipsec_sa_common_param_fill(union roc_ot_ipsec_sa_word2 *w2,
11                               uint8_t *cipher_key, uint8_t *salt_key,
12                               struct rte_security_ipsec_xform *ipsec_xfrm,
13                               struct rte_crypto_sym_xform *crypto_xfrm)
14 {
15         const uint8_t *key;
16         uint32_t *tmp_salt;
17         uint64_t *tmp_key;
18         int length, i;
19
20         /* Set direction */
21         switch (ipsec_xfrm->direction) {
22         case RTE_SECURITY_IPSEC_SA_DIR_INGRESS:
23                 w2->s.dir = ROC_IE_OT_SA_DIR_INBOUND;
24                 break;
25         case RTE_SECURITY_IPSEC_SA_DIR_EGRESS:
26                 w2->s.dir = ROC_IE_OT_SA_DIR_OUTBOUND;
27                 break;
28         default:
29                 return -EINVAL;
30         }
31
32         /* Set protocol - ESP vs AH */
33         switch (ipsec_xfrm->proto) {
34         case RTE_SECURITY_IPSEC_SA_PROTO_ESP:
35                 w2->s.protocol = ROC_IE_OT_SA_PROTOCOL_ESP;
36                 break;
37         case RTE_SECURITY_IPSEC_SA_PROTO_AH:
38                 w2->s.protocol = ROC_IE_OT_SA_PROTOCOL_AH;
39                 break;
40         default:
41                 return -EINVAL;
42         }
43
44         /* Set mode - transport vs tunnel */
45         switch (ipsec_xfrm->mode) {
46         case RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT:
47                 w2->s.mode = ROC_IE_OT_SA_MODE_TRANSPORT;
48                 break;
49         case RTE_SECURITY_IPSEC_SA_MODE_TUNNEL:
50                 w2->s.mode = ROC_IE_OT_SA_MODE_TUNNEL;
51                 break;
52         default:
53                 return -EINVAL;
54         }
55
56         /* Set encryption algorithm */
57         if (crypto_xfrm->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
58                 key = crypto_xfrm->aead.key.data;
59                 length = crypto_xfrm->aead.key.length;
60
61                 switch (crypto_xfrm->aead.algo) {
62                 case RTE_CRYPTO_AEAD_AES_GCM:
63                         w2->s.enc_type = ROC_IE_OT_SA_ENC_AES_GCM;
64                         w2->s.auth_type = ROC_IE_OT_SA_AUTH_NULL;
65                         memcpy(salt_key, &ipsec_xfrm->salt, 4);
66                         tmp_salt = (uint32_t *)salt_key;
67                         *tmp_salt = rte_be_to_cpu_32(*tmp_salt);
68                         break;
69                 default:
70                         return -ENOTSUP;
71                 }
72         } else {
73                 return -ENOTSUP;
74         }
75
76         /* Set encapsulation type */
77         if (ipsec_xfrm->options.udp_encap)
78                 w2->s.encap_type = ROC_IE_OT_SA_ENCAP_UDP;
79
80         w2->s.spi = ipsec_xfrm->spi;
81
82         /* Copy encryption key */
83         memcpy(cipher_key, key, length);
84         tmp_key = (uint64_t *)cipher_key;
85         for (i = 0; i < (int)(ROC_CTX_MAX_CKEY_LEN / sizeof(uint64_t)); i++)
86                 tmp_key[i] = rte_be_to_cpu_64(tmp_key[i]);
87
88         switch (length) {
89         case ROC_CPT_AES128_KEY_LEN:
90                 w2->s.aes_key_len = ROC_IE_OT_SA_AES_KEY_LEN_128;
91                 break;
92         case ROC_CPT_AES192_KEY_LEN:
93                 w2->s.aes_key_len = ROC_IE_OT_SA_AES_KEY_LEN_192;
94                 break;
95         case ROC_CPT_AES256_KEY_LEN:
96                 w2->s.aes_key_len = ROC_IE_OT_SA_AES_KEY_LEN_256;
97                 break;
98         default:
99                 return -EINVAL;
100         }
101
102         return 0;
103 }
104
105 static size_t
106 ot_ipsec_inb_ctx_size(struct roc_ot_ipsec_inb_sa *sa)
107 {
108         size_t size;
109
110         /* Variable based on Anti-replay Window */
111         size = offsetof(struct roc_ot_ipsec_inb_sa, ctx) +
112                offsetof(struct roc_ot_ipsec_inb_ctx_update_reg, ar_winbits);
113
114         if (sa->w0.s.ar_win)
115                 size += (1 << (sa->w0.s.ar_win - 1)) * sizeof(uint64_t);
116
117         return size;
118 }
119
120 int
121 cnxk_ot_ipsec_inb_sa_fill(struct roc_ot_ipsec_inb_sa *sa,
122                           struct rte_security_ipsec_xform *ipsec_xfrm,
123                           struct rte_crypto_sym_xform *crypto_xfrm)
124 {
125         union roc_ot_ipsec_sa_word2 w2;
126         uint32_t replay_win_sz;
127         size_t offset;
128         int rc;
129
130         w2.u64 = 0;
131         rc = ot_ipsec_sa_common_param_fill(&w2, sa->cipher_key, sa->w8.s.salt,
132                                            ipsec_xfrm, crypto_xfrm);
133         if (rc)
134                 return rc;
135
136         /* Updata common word2 data */
137         sa->w2.u64 = w2.u64;
138
139         /* Only support power-of-two window sizes supported */
140         replay_win_sz = ipsec_xfrm->replay_win_sz;
141         if (replay_win_sz) {
142                 if (!rte_is_power_of_2(replay_win_sz) ||
143                     replay_win_sz > ROC_AR_WIN_SIZE_MAX)
144                         return -ENOTSUP;
145
146                 sa->w0.s.ar_win = rte_log2_u32(replay_win_sz) - 5;
147         }
148
149         /* Default options for pkt_out and pkt_fmt are with
150          * second pass meta and no defrag.
151          */
152         sa->w0.s.pkt_format = ROC_IE_OT_SA_PKT_FMT_META;
153         sa->w0.s.pkt_output = ROC_IE_OT_SA_PKT_OUTPUT_HW_BASED_DEFRAG;
154         sa->w0.s.pkind = ROC_OT_CPT_META_PKIND;
155
156         /* ESN */
157         sa->w2.s.esn_en = !!ipsec_xfrm->options.esn;
158         if (ipsec_xfrm->options.udp_encap) {
159                 sa->w10.s.udp_src_port = 4500;
160                 sa->w10.s.udp_dst_port = 4500;
161         }
162
163         offset = offsetof(struct roc_ot_ipsec_inb_sa, ctx);
164         /* Word offset for HW managed SA field */
165         sa->w0.s.hw_ctx_off = offset / 8;
166         /* Context push size for inbound spans up to hw_ctx including
167          * ar_base field, in 8b units
168          */
169         sa->w0.s.ctx_push_size = sa->w0.s.hw_ctx_off + 1;
170         /* Entire context size in 128B units */
171         sa->w0.s.ctx_size =
172                 (PLT_ALIGN_CEIL(ot_ipsec_inb_ctx_size(sa), ROC_CTX_UNIT_128B) /
173                  ROC_CTX_UNIT_128B) -
174                 1;
175
176         /* There are two words of CPT_CTX_HW_S for ucode to skip */
177         sa->w0.s.ctx_hdr_size = 1;
178         sa->w0.s.aop_valid = 1;
179
180         rte_wmb();
181
182         /* Enable SA */
183         sa->w2.s.valid = 1;
184         return 0;
185 }
186
187 int
188 cnxk_ot_ipsec_outb_sa_fill(struct roc_ot_ipsec_outb_sa *sa,
189                            struct rte_security_ipsec_xform *ipsec_xfrm,
190                            struct rte_crypto_sym_xform *crypto_xfrm)
191 {
192         struct rte_security_ipsec_tunnel_param *tunnel = &ipsec_xfrm->tunnel;
193         union roc_ot_ipsec_sa_word2 w2;
194         size_t offset;
195         int rc;
196
197         w2.u64 = 0;
198         rc = ot_ipsec_sa_common_param_fill(&w2, sa->cipher_key, sa->iv.s.salt,
199                                            ipsec_xfrm, crypto_xfrm);
200         if (rc)
201                 return rc;
202
203         /* Update common word2 data */
204         sa->w2.u64 = w2.u64;
205
206         if (ipsec_xfrm->mode != RTE_SECURITY_IPSEC_SA_MODE_TUNNEL)
207                 goto skip_tunnel_info;
208
209         /* Tunnel header info */
210         switch (tunnel->type) {
211         case RTE_SECURITY_IPSEC_TUNNEL_IPV4:
212                 sa->w2.s.outer_ip_ver = ROC_IE_OT_SA_IP_VERSION_4;
213                 memcpy(&sa->outer_hdr.ipv4.src_addr, &tunnel->ipv4.src_ip,
214                        sizeof(struct in_addr));
215                 memcpy(&sa->outer_hdr.ipv4.dst_addr, &tunnel->ipv4.dst_ip,
216                        sizeof(struct in_addr));
217
218                 /* IP Source and Dest seems to be in LE/CPU endian */
219                 sa->outer_hdr.ipv4.src_addr =
220                         rte_be_to_cpu_32(sa->outer_hdr.ipv4.src_addr);
221                 sa->outer_hdr.ipv4.dst_addr =
222                         rte_be_to_cpu_32(sa->outer_hdr.ipv4.dst_addr);
223
224                 /* Outer header DF bit source */
225                 if (!ipsec_xfrm->options.copy_df) {
226                         sa->w2.s.ipv4_df_src_or_ipv6_flw_lbl_src =
227                                 ROC_IE_OT_SA_COPY_FROM_SA;
228                         sa->w10.s.ipv4_df_or_ipv6_flw_lbl = tunnel->ipv4.df;
229                 } else {
230                         sa->w2.s.ipv4_df_src_or_ipv6_flw_lbl_src =
231                                 ROC_IE_OT_SA_COPY_FROM_INNER_IP_HDR;
232                 }
233
234                 /* Outer header DSCP source */
235                 if (!ipsec_xfrm->options.copy_dscp) {
236                         sa->w2.s.dscp_src = ROC_IE_OT_SA_COPY_FROM_SA;
237                         sa->w10.s.dscp = tunnel->ipv4.dscp;
238                 } else {
239                         sa->w2.s.dscp_src = ROC_IE_OT_SA_COPY_FROM_INNER_IP_HDR;
240                 }
241                 break;
242         case RTE_SECURITY_IPSEC_TUNNEL_IPV6:
243                 sa->w2.s.outer_ip_ver = ROC_IE_OT_SA_IP_VERSION_6;
244                 memcpy(&sa->outer_hdr.ipv6.src_addr, &tunnel->ipv6.src_addr,
245                        sizeof(struct in6_addr));
246                 memcpy(&sa->outer_hdr.ipv6.dst_addr, &tunnel->ipv6.dst_addr,
247                        sizeof(struct in6_addr));
248
249                 /* Outer header flow label source */
250                 if (!ipsec_xfrm->options.copy_flabel) {
251                         sa->w2.s.ipv4_df_src_or_ipv6_flw_lbl_src =
252                                 ROC_IE_OT_SA_COPY_FROM_SA;
253
254                         sa->w10.s.ipv4_df_or_ipv6_flw_lbl = tunnel->ipv6.flabel;
255                 } else {
256                         sa->w2.s.ipv4_df_src_or_ipv6_flw_lbl_src =
257                                 ROC_IE_OT_SA_COPY_FROM_INNER_IP_HDR;
258                 }
259
260                 /* Outer header DSCP source */
261                 if (!ipsec_xfrm->options.copy_dscp) {
262                         sa->w2.s.dscp_src = ROC_IE_OT_SA_COPY_FROM_SA;
263                         sa->w10.s.dscp = tunnel->ipv6.dscp;
264                 } else {
265                         sa->w2.s.dscp_src = ROC_IE_OT_SA_COPY_FROM_INNER_IP_HDR;
266                 }
267                 break;
268         default:
269                 return -EINVAL;
270         }
271
272         /* Default options of DSCP and Flow label/DF */
273         sa->w2.s.dscp_src = ROC_IE_OT_SA_COPY_FROM_SA;
274         sa->w2.s.ipv4_df_src_or_ipv6_flw_lbl_src = ROC_IE_OT_SA_COPY_FROM_SA;
275
276 skip_tunnel_info:
277         /* ESN */
278         sa->w0.s.esn_en = !!ipsec_xfrm->options.esn;
279
280         if (ipsec_xfrm->options.udp_encap) {
281                 sa->w10.s.udp_src_port = 4500;
282                 sa->w10.s.udp_dst_port = 4500;
283         }
284
285         offset = offsetof(struct roc_ot_ipsec_outb_sa, ctx);
286         /* Word offset for HW managed SA field */
287         sa->w0.s.hw_ctx_off = offset / 8;
288         /* Context push size is up to hmac_opad_ipad */
289         sa->w0.s.ctx_push_size = sa->w0.s.hw_ctx_off;
290         /* Entire context size in 128B units */
291         offset = sizeof(struct roc_ot_ipsec_outb_sa);
292         sa->w0.s.ctx_size = (PLT_ALIGN_CEIL(offset, ROC_CTX_UNIT_128B) /
293                              ROC_CTX_UNIT_128B) -
294                             1;
295
296         /* IPID gen */
297         sa->w2.s.ipid_gen = 1;
298
299         /* There are two words of CPT_CTX_HW_S for ucode to skip */
300         sa->w0.s.ctx_hdr_size = 1;
301         sa->w0.s.aop_valid = 1;
302
303         rte_wmb();
304
305         /* Enable SA */
306         sa->w2.s.valid = 1;
307         return 0;
308 }
309
310 bool
311 cnxk_ot_ipsec_inb_sa_valid(struct roc_ot_ipsec_inb_sa *sa)
312 {
313         return !!sa->w2.s.valid;
314 }
315
316 bool
317 cnxk_ot_ipsec_outb_sa_valid(struct roc_ot_ipsec_outb_sa *sa)
318 {
319         return !!sa->w2.s.valid;
320 }
321
322 uint8_t
323 cnxk_ipsec_ivlen_get(enum rte_crypto_cipher_algorithm c_algo,
324                      enum rte_crypto_auth_algorithm a_algo,
325                      enum rte_crypto_aead_algorithm aead_algo)
326 {
327         uint8_t ivlen = 0;
328
329         if (aead_algo == RTE_CRYPTO_AEAD_AES_GCM)
330                 ivlen = 8;
331
332         switch (c_algo) {
333         case RTE_CRYPTO_CIPHER_AES_CTR:
334                 ivlen = 8;
335                 break;
336         case RTE_CRYPTO_CIPHER_3DES_CBC:
337                 ivlen = ROC_CPT_DES_BLOCK_LENGTH;
338                 break;
339         case RTE_CRYPTO_CIPHER_AES_CBC:
340                 ivlen = ROC_CPT_AES_BLOCK_LENGTH;
341                 break;
342         default:
343                 break;
344         }
345
346         switch (a_algo) {
347         case RTE_CRYPTO_AUTH_AES_GMAC:
348                 ivlen = 8;
349                 break;
350         default:
351                 break;
352         }
353
354         return ivlen;
355 }
356
357 uint8_t
358 cnxk_ipsec_icvlen_get(enum rte_crypto_cipher_algorithm c_algo,
359                       enum rte_crypto_auth_algorithm a_algo,
360                       enum rte_crypto_aead_algorithm aead_algo)
361 {
362         uint8_t icv = 0;
363
364         (void)c_algo;
365
366         switch (a_algo) {
367         case RTE_CRYPTO_AUTH_NULL:
368                 icv = 0;
369                 break;
370         case RTE_CRYPTO_AUTH_SHA1_HMAC:
371                 icv = 12;
372                 break;
373         case RTE_CRYPTO_AUTH_SHA256_HMAC:
374         case RTE_CRYPTO_AUTH_AES_GMAC:
375                 icv = 16;
376                 break;
377         case RTE_CRYPTO_AUTH_SHA384_HMAC:
378                 icv = 24;
379                 break;
380         case RTE_CRYPTO_AUTH_SHA512_HMAC:
381                 icv = 32;
382                 break;
383         default:
384                 break;
385         }
386
387         switch (aead_algo) {
388         case RTE_CRYPTO_AEAD_AES_GCM:
389                 icv = 16;
390                 break;
391         default:
392                 break;
393         }
394
395         return icv;
396 }
397
398 uint8_t
399 cnxk_ipsec_outb_roundup_byte(enum rte_crypto_cipher_algorithm c_algo,
400                              enum rte_crypto_aead_algorithm aead_algo)
401 {
402         uint8_t roundup_byte = 4;
403
404         if (aead_algo == RTE_CRYPTO_AEAD_AES_GCM)
405                 return roundup_byte;
406
407         switch (c_algo) {
408         case RTE_CRYPTO_CIPHER_AES_CTR:
409                 roundup_byte = 4;
410                 break;
411         case RTE_CRYPTO_CIPHER_AES_CBC:
412                 roundup_byte = 16;
413                 break;
414         case RTE_CRYPTO_CIPHER_3DES_CBC:
415                 roundup_byte = 8;
416                 break;
417         case RTE_CRYPTO_CIPHER_NULL:
418                 roundup_byte = 4;
419                 break;
420         default:
421                 break;
422         }
423
424         return roundup_byte;
425 }
426
427 int
428 cnxk_ipsec_outb_rlens_get(struct cnxk_ipsec_outb_rlens *rlens,
429                           struct rte_security_ipsec_xform *ipsec_xfrm,
430                           struct rte_crypto_sym_xform *crypto_xfrm)
431 {
432         struct rte_security_ipsec_tunnel_param *tunnel = &ipsec_xfrm->tunnel;
433         enum rte_crypto_cipher_algorithm c_algo = RTE_CRYPTO_CIPHER_NULL;
434         enum rte_crypto_auth_algorithm a_algo = RTE_CRYPTO_AUTH_NULL;
435         enum rte_crypto_aead_algorithm aead_algo = 0;
436         uint16_t partial_len = 0;
437         uint8_t roundup_byte = 0;
438         int8_t roundup_len = 0;
439
440         memset(rlens, 0, sizeof(struct cnxk_ipsec_outb_rlens));
441
442         /* Get Cipher and Auth algo */
443         if (crypto_xfrm->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
444                 aead_algo = crypto_xfrm->aead.algo;
445         } else {
446                 if (crypto_xfrm->type == RTE_CRYPTO_SYM_XFORM_CIPHER)
447                         c_algo = crypto_xfrm->cipher.algo;
448                 else
449                         a_algo = crypto_xfrm->auth.algo;
450
451                 if (crypto_xfrm->next) {
452                         if (crypto_xfrm->next->type ==
453                             RTE_CRYPTO_SYM_XFORM_CIPHER)
454                                 c_algo = crypto_xfrm->next->cipher.algo;
455                         else
456                                 a_algo = crypto_xfrm->next->auth.algo;
457                 }
458         }
459
460         if (ipsec_xfrm->proto == RTE_SECURITY_IPSEC_SA_PROTO_ESP) {
461                 partial_len = ROC_CPT_ESP_HDR_LEN;
462                 roundup_len = ROC_CPT_ESP_TRL_LEN;
463         } else {
464                 partial_len = ROC_CPT_AH_HDR_LEN;
465         }
466
467         if (ipsec_xfrm->mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
468                 if (tunnel->type == RTE_SECURITY_IPSEC_TUNNEL_IPV4)
469                         partial_len += ROC_CPT_TUNNEL_IPV4_HDR_LEN;
470                 else
471                         partial_len += ROC_CPT_TUNNEL_IPV6_HDR_LEN;
472         }
473
474         partial_len += cnxk_ipsec_ivlen_get(c_algo, a_algo, aead_algo);
475         partial_len += cnxk_ipsec_icvlen_get(c_algo, a_algo, aead_algo);
476         roundup_byte = cnxk_ipsec_outb_roundup_byte(c_algo, aead_algo);
477
478         if (ipsec_xfrm->options.udp_encap)
479                 partial_len += sizeof(struct rte_udp_hdr);
480
481         rlens->partial_len = partial_len;
482         rlens->roundup_len = roundup_len;
483         rlens->roundup_byte = roundup_byte;
484         rlens->max_extended_len = partial_len + roundup_len + roundup_byte;
485         return 0;
486 }