Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (c) 2023 Corigine Systems, Inc.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include <stdalign.h>
7 : :
8 : : #include "nfp_ipsec.h"
9 : :
10 : : #include <rte_cryptodev.h>
11 : : #include <rte_malloc.h>
12 : : #include <rte_security_driver.h>
13 : :
14 : : #include <ethdev_driver.h>
15 : : #include <ethdev_pci.h>
16 : :
17 : : #include "nfp_logs.h"
18 : : #include "nfp_net_common.h"
19 : : #include "nfp_net_ctrl.h"
20 : : #include "nfp_rxtx.h"
21 : :
22 : : #define NFP_UDP_ESP_PORT 4500
23 : :
24 : : static const struct rte_cryptodev_capabilities nfp_crypto_caps[] = {
25 : : {
26 : : .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
27 : : .sym = {
28 : : .xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
29 : : .auth = {
30 : : .algo = RTE_CRYPTO_AUTH_MD5_HMAC,
31 : : .block_size = 64,
32 : : .key_size = {
33 : : .min = 16,
34 : : .max = 16,
35 : : .increment = 0
36 : : },
37 : : .digest_size = {
38 : : .min = 12,
39 : : .max = 16,
40 : : .increment = 4
41 : : },
42 : : },
43 : : },
44 : : },
45 : : {
46 : : .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
47 : : .sym = {
48 : : .xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
49 : : .auth = {
50 : : .algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
51 : : .block_size = 64,
52 : : .key_size = {
53 : : .min = 20,
54 : : .max = 64,
55 : : .increment = 1
56 : : },
57 : : .digest_size = {
58 : : .min = 10,
59 : : .max = 12,
60 : : .increment = 2
61 : : },
62 : : },
63 : : },
64 : : },
65 : : {
66 : : .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
67 : : .sym = {
68 : : .xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
69 : : .auth = {
70 : : .algo = RTE_CRYPTO_AUTH_SHA256_HMAC,
71 : : .block_size = 64,
72 : : .key_size = {
73 : : .min = 32,
74 : : .max = 32,
75 : : .increment = 0
76 : : },
77 : : .digest_size = {
78 : : .min = 12,
79 : : .max = 16,
80 : : .increment = 4
81 : : },
82 : : },
83 : : },
84 : : },
85 : : {
86 : : .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
87 : : .sym = {
88 : : .xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
89 : : .auth = {
90 : : .algo = RTE_CRYPTO_AUTH_SHA384_HMAC,
91 : : .block_size = 128,
92 : : .key_size = {
93 : : .min = 48,
94 : : .max = 48,
95 : : .increment = 0
96 : : },
97 : : .digest_size = {
98 : : .min = 12,
99 : : .max = 24,
100 : : .increment = 12
101 : : },
102 : : },
103 : : },
104 : : },
105 : : {
106 : : .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
107 : : .sym = {
108 : : .xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
109 : : .auth = {
110 : : .algo = RTE_CRYPTO_AUTH_SHA512_HMAC,
111 : : .block_size = 128,
112 : : .key_size = {
113 : : .min = 64,
114 : : .max = 64,
115 : : .increment = 1
116 : : },
117 : : .digest_size = {
118 : : .min = 12,
119 : : .max = 32,
120 : : .increment = 4
121 : : },
122 : : },
123 : : },
124 : : },
125 : : {
126 : : .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
127 : : .sym = {
128 : : .xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
129 : : .cipher = {
130 : : .algo = RTE_CRYPTO_CIPHER_3DES_CBC,
131 : : .block_size = 8,
132 : : .key_size = {
133 : : .min = 24,
134 : : .max = 24,
135 : : .increment = 0
136 : : },
137 : : .iv_size = {
138 : : .min = 8,
139 : : .max = 16,
140 : : .increment = 8
141 : : },
142 : : },
143 : : },
144 : : },
145 : : {
146 : : .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
147 : : .sym = {
148 : : .xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
149 : : .cipher = {
150 : : .algo = RTE_CRYPTO_CIPHER_AES_CBC,
151 : : .block_size = 16,
152 : : .key_size = {
153 : : .min = 16,
154 : : .max = 32,
155 : : .increment = 8
156 : : },
157 : : .iv_size = {
158 : : .min = 8,
159 : : .max = 16,
160 : : .increment = 8
161 : : },
162 : : },
163 : : },
164 : : },
165 : : {
166 : : .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
167 : : .sym = {
168 : : .xform_type = RTE_CRYPTO_SYM_XFORM_AEAD,
169 : : .aead = {
170 : : .algo = RTE_CRYPTO_AEAD_AES_GCM,
171 : : .block_size = 16,
172 : : .key_size = {
173 : : .min = 16,
174 : : .max = 32,
175 : : .increment = 8
176 : : },
177 : : .digest_size = {
178 : : .min = 16,
179 : : .max = 16,
180 : : .increment = 0
181 : : },
182 : : .aad_size = {
183 : : .min = 0,
184 : : .max = 1024,
185 : : .increment = 1
186 : : },
187 : : .iv_size = {
188 : : .min = 8,
189 : : .max = 16,
190 : : .increment = 4
191 : : }
192 : : },
193 : : },
194 : : },
195 : : {
196 : : .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
197 : : .sym = {
198 : : .xform_type = RTE_CRYPTO_SYM_XFORM_AEAD,
199 : : .aead = {
200 : : .algo = RTE_CRYPTO_AEAD_CHACHA20_POLY1305,
201 : : .block_size = 16,
202 : : .key_size = {
203 : : .min = 32,
204 : : .max = 32,
205 : : .increment = 0
206 : : },
207 : : .digest_size = {
208 : : .min = 16,
209 : : .max = 16,
210 : : .increment = 0
211 : : },
212 : : .aad_size = {
213 : : .min = 0,
214 : : .max = 1024,
215 : : .increment = 1
216 : : },
217 : : .iv_size = {
218 : : .min = 8,
219 : : .max = 16,
220 : : .increment = 4
221 : : }
222 : : },
223 : : },
224 : : },
225 : : {
226 : : .op = RTE_CRYPTO_OP_TYPE_UNDEFINED,
227 : : .sym = {
228 : : .xform_type = RTE_CRYPTO_SYM_XFORM_NOT_SPECIFIED
229 : : },
230 : : }
231 : : };
232 : :
233 : : static const struct rte_security_capability nfp_security_caps[] = {
234 : : { /* IPsec Inline Crypto Tunnel Egress */
235 : : .action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
236 : : .protocol = RTE_SECURITY_PROTOCOL_IPSEC,
237 : : .ipsec = {
238 : : .mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL,
239 : : .direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS,
240 : : .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
241 : : .options = {
242 : : .udp_encap = 1,
243 : : .stats = 1,
244 : : .esn = 1
245 : : }
246 : : },
247 : : .crypto_capabilities = nfp_crypto_caps,
248 : : .ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA
249 : : },
250 : : { /* IPsec Inline Crypto Tunnel Ingress */
251 : : .action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
252 : : .protocol = RTE_SECURITY_PROTOCOL_IPSEC,
253 : : .ipsec = {
254 : : .mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL,
255 : : .direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS,
256 : : .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
257 : : .options = {
258 : : .udp_encap = 1,
259 : : .stats = 1,
260 : : .esn = 1
261 : : }
262 : : },
263 : : .crypto_capabilities = nfp_crypto_caps
264 : : },
265 : : { /* IPsec Inline Crypto Transport Egress */
266 : : .action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
267 : : .protocol = RTE_SECURITY_PROTOCOL_IPSEC,
268 : : .ipsec = {
269 : : .mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
270 : : .direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS,
271 : : .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
272 : : .options = {
273 : : .udp_encap = 1,
274 : : .stats = 1,
275 : : .esn = 1
276 : : }
277 : : },
278 : : .crypto_capabilities = nfp_crypto_caps,
279 : : .ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA
280 : : },
281 : : { /* IPsec Inline Crypto Transport Ingress */
282 : : .action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
283 : : .protocol = RTE_SECURITY_PROTOCOL_IPSEC,
284 : : .ipsec = {
285 : : .mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
286 : : .direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS,
287 : : .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
288 : : .options = {
289 : : .udp_encap = 1,
290 : : .stats = 1,
291 : : .esn = 1
292 : : }
293 : : },
294 : : .crypto_capabilities = nfp_crypto_caps
295 : : },
296 : : { /* IPsec Inline Protocol Tunnel Egress */
297 : : .action = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL,
298 : : .protocol = RTE_SECURITY_PROTOCOL_IPSEC,
299 : : .ipsec = {
300 : : .mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL,
301 : : .direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS,
302 : : .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
303 : : .options = {
304 : : .udp_encap = 1,
305 : : .stats = 1,
306 : : .esn = 1
307 : : }
308 : : },
309 : : .crypto_capabilities = nfp_crypto_caps,
310 : : .ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA
311 : : },
312 : : { /* IPsec Inline Protocol Tunnel Ingress */
313 : : .action = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL,
314 : : .protocol = RTE_SECURITY_PROTOCOL_IPSEC,
315 : : .ipsec = {
316 : : .mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL,
317 : : .direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS,
318 : : .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
319 : : .options = {
320 : : .udp_encap = 1,
321 : : .stats = 1,
322 : : .esn = 1
323 : : }
324 : : },
325 : : .crypto_capabilities = nfp_crypto_caps
326 : : },
327 : : { /* IPsec Inline Protocol Transport Egress */
328 : : .action = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL,
329 : : .protocol = RTE_SECURITY_PROTOCOL_IPSEC,
330 : : .ipsec = {
331 : : .mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
332 : : .direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS,
333 : : .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
334 : : .options = {
335 : : .udp_encap = 1,
336 : : .stats = 1,
337 : : .esn = 1
338 : : }
339 : : },
340 : : .crypto_capabilities = nfp_crypto_caps,
341 : : .ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA
342 : : },
343 : : { /* IPsec Inline Protocol Transport Ingress */
344 : : .action = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL,
345 : : .protocol = RTE_SECURITY_PROTOCOL_IPSEC,
346 : : .ipsec = {
347 : : .mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
348 : : .direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS,
349 : : .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
350 : : .options = {
351 : : .udp_encap = 1,
352 : : .stats = 1,
353 : : .esn = 1
354 : : }
355 : : },
356 : : .crypto_capabilities = nfp_crypto_caps
357 : : },
358 : : {
359 : : .action = RTE_SECURITY_ACTION_TYPE_NONE
360 : : }
361 : : };
362 : :
363 : : /* IPsec config message cmd codes */
364 : : enum nfp_ipsec_cfg_msg_cmd_codes {
365 : : NFP_IPSEC_CFG_MSG_ADD_SA, /**< Add a new SA */
366 : : NFP_IPSEC_CFG_MSG_INV_SA, /**< Invalidate an existing SA */
367 : : NFP_IPSEC_CFG_MSG_MODIFY_SA, /**< Modify an existing SA */
368 : : NFP_IPSEC_CFG_MSG_GET_SA_STATS, /**< Report SA counters, flags, etc. */
369 : : NFP_IPSEC_CFG_MSG_GET_SEQ_NUMS, /**< Allocate sequence numbers */
370 : : NFP_IPSEC_CFG_MSG_LAST
371 : : };
372 : :
373 : : enum nfp_ipsec_cfg_msg_rsp_codes {
374 : : NFP_IPSEC_CFG_MSG_OK,
375 : : NFP_IPSEC_CFG_MSG_FAILED,
376 : : NFP_IPSEC_CFG_MSG_SA_VALID,
377 : : NFP_IPSEC_CFG_MSG_SA_HASH_ADD_FAILED,
378 : : NFP_IPSEC_CFG_MSG_SA_HASH_DEL_FAILED,
379 : : NFP_IPSEC_CFG_MSG_SA_INVALID_CMD
380 : : };
381 : :
382 : : enum nfp_ipsec_mode {
383 : : NFP_IPSEC_MODE_TRANSPORT,
384 : : NFP_IPSEC_MODE_TUNNEL,
385 : : };
386 : :
387 : : enum nfp_ipsec_protocol {
388 : : NFP_IPSEC_PROTOCOL_AH,
389 : : NFP_IPSEC_PROTOCOL_ESP,
390 : : };
391 : :
392 : : /* Cipher modes */
393 : : enum nfp_ipsec_cimode {
394 : : NFP_IPSEC_CIMODE_ECB,
395 : : NFP_IPSEC_CIMODE_CBC,
396 : : NFP_IPSEC_CIMODE_CFB,
397 : : NFP_IPSEC_CIMODE_OFB,
398 : : NFP_IPSEC_CIMODE_CTR,
399 : : };
400 : :
401 : : /* Hash types */
402 : : enum nfp_ipsec_hash_type {
403 : : NFP_IPSEC_HASH_NONE,
404 : : NFP_IPSEC_HASH_MD5_96,
405 : : NFP_IPSEC_HASH_SHA1_96,
406 : : NFP_IPSEC_HASH_SHA256_96,
407 : : NFP_IPSEC_HASH_SHA384_96,
408 : : NFP_IPSEC_HASH_SHA512_96,
409 : : NFP_IPSEC_HASH_MD5_128,
410 : : NFP_IPSEC_HASH_SHA1_80,
411 : : NFP_IPSEC_HASH_SHA256_128,
412 : : NFP_IPSEC_HASH_SHA384_192,
413 : : NFP_IPSEC_HASH_SHA512_256,
414 : : NFP_IPSEC_HASH_GF128_128,
415 : : NFP_IPSEC_HASH_POLY1305_128,
416 : : };
417 : :
418 : : /* Cipher types */
419 : : enum nfp_ipsec_cipher_type {
420 : : NFP_IPSEC_CIPHER_NULL,
421 : : NFP_IPSEC_CIPHER_3DES,
422 : : NFP_IPSEC_CIPHER_AES128,
423 : : NFP_IPSEC_CIPHER_AES192,
424 : : NFP_IPSEC_CIPHER_AES256,
425 : : NFP_IPSEC_CIPHER_AES128_NULL,
426 : : NFP_IPSEC_CIPHER_AES192_NULL,
427 : : NFP_IPSEC_CIPHER_AES256_NULL,
428 : : NFP_IPSEC_CIPHER_CHACHA20,
429 : : };
430 : :
431 : : /* Don't Fragment types */
432 : : enum nfp_ipsec_df_type {
433 : : NFP_IPSEC_DF_CLEAR,
434 : : NFP_IPSEC_DF_SET,
435 : : NFP_IPSEC_DF_COPY,
436 : : };
437 : :
438 : : static int
439 : 0 : nfp_ipsec_cfg_cmd_issue(struct nfp_net_hw *net_hw,
440 : : struct nfp_ipsec_msg *msg)
441 : : {
442 : : int ret;
443 : : uint32_t i;
444 : : uint32_t msg_size;
445 : :
446 : : msg_size = RTE_DIM(msg->raw);
447 : 0 : msg->rsp = NFP_IPSEC_CFG_MSG_OK;
448 : :
449 [ # # ]: 0 : for (i = 0; i < msg_size; i++)
450 : 0 : nn_cfg_writel(&net_hw->super, NFP_NET_CFG_MBOX_VAL + 4 * i, msg->raw[i]);
451 : :
452 : 0 : ret = nfp_net_mbox_reconfig(net_hw, NFP_NET_CFG_MBOX_CMD_IPSEC);
453 [ # # ]: 0 : if (ret < 0) {
454 : 0 : PMD_DRV_LOG(ERR, "Failed to IPsec reconfig mbox");
455 : 0 : return ret;
456 : : }
457 : :
458 : : /*
459 : : * Not all commands and callers make use of response message data. But
460 : : * leave this up to the caller and always read and store the full
461 : : * response. One example where the data is needed is for statistics.
462 : : */
463 [ # # ]: 0 : for (i = 0; i < msg_size; i++)
464 : 0 : msg->raw[i] = nn_cfg_readl(&net_hw->super, NFP_NET_CFG_MBOX_VAL + 4 * i);
465 : :
466 [ # # ]: 0 : switch (msg->rsp) {
467 : : case NFP_IPSEC_CFG_MSG_OK:
468 : : ret = 0;
469 : : break;
470 : : case NFP_IPSEC_CFG_MSG_SA_INVALID_CMD:
471 : : ret = -EINVAL;
472 : : break;
473 : : case NFP_IPSEC_CFG_MSG_SA_VALID:
474 : : ret = -EEXIST;
475 : : break;
476 : : case NFP_IPSEC_CFG_MSG_FAILED:
477 : : /* FALLTHROUGH */
478 : : case NFP_IPSEC_CFG_MSG_SA_HASH_ADD_FAILED:
479 : : /* FALLTHROUGH */
480 : : case NFP_IPSEC_CFG_MSG_SA_HASH_DEL_FAILED:
481 : : ret = -EIO;
482 : : break;
483 : : default:
484 : : ret = -EDOM;
485 : : }
486 : :
487 : : return ret;
488 : : }
489 : :
490 : : /**
491 : : * Get valid SA index from SA table
492 : : *
493 : : * @param data
494 : : * SA table pointer
495 : : * @param sa_idx
496 : : * SA table index pointer
497 : : *
498 : : * @return
499 : : * Negative number on full or repeat, 0 on success
500 : : *
501 : : * Note: multiple sockets may create same SA session.
502 : : */
503 : : static void
504 : : nfp_get_sa_entry(struct nfp_net_ipsec_data *data,
505 : : int *sa_idx)
506 : : {
507 : : uint32_t i;
508 : :
509 [ # # ]: 0 : for (i = 0; i < NFP_NET_IPSEC_MAX_SA_CNT; i++) {
510 [ # # ]: 0 : if (data->sa_entries[i] == NULL) {
511 : 0 : *sa_idx = i;
512 : 0 : break;
513 : : }
514 : : }
515 : : }
516 : :
517 : : static void
518 : 0 : nfp_aesgcm_iv_update(struct ipsec_add_sa *cfg,
519 : : uint16_t iv_len,
520 : : const char *iv_string)
521 : : {
522 : : int i;
523 : : char *save;
524 : : char *iv_b;
525 : : char *iv_str;
526 : : uint8_t *cfg_iv;
527 : :
528 : 0 : iv_str = strdup(iv_string);
529 [ # # ]: 0 : if (iv_str == NULL) {
530 : 0 : PMD_DRV_LOG(ERR, "Failed to strdup iv_string");
531 : 0 : return;
532 : : }
533 : :
534 : 0 : cfg_iv = (uint8_t *)cfg->aesgcm_fields.iv;
535 : :
536 [ # # ]: 0 : for (i = 0; i < iv_len; i++) {
537 [ # # ]: 0 : iv_b = strtok_r(i ? NULL : iv_str, ",", &save);
538 [ # # ]: 0 : if (iv_b == NULL)
539 : : break;
540 : :
541 : 0 : cfg_iv[i] = strtoul(iv_b, NULL, 0);
542 : : }
543 : :
544 [ # # ]: 0 : *(uint32_t *)cfg_iv = rte_be_to_cpu_32(*(uint32_t *)cfg_iv);
545 [ # # ]: 0 : *(uint32_t *)&cfg_iv[4] = rte_be_to_cpu_32(*(uint32_t *)&cfg_iv[4]);
546 : :
547 : 0 : free(iv_str);
548 : : }
549 : :
550 : : static int
551 : 0 : set_aes_keylen(uint32_t key_length,
552 : : struct ipsec_add_sa *cfg)
553 : : {
554 [ # # # # ]: 0 : switch (key_length << 3) {
555 : 0 : case 128:
556 : 0 : cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_AES128;
557 : 0 : break;
558 : 0 : case 192:
559 : 0 : cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_AES192;
560 : 0 : break;
561 : 0 : case 256:
562 : 0 : cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_AES256;
563 : 0 : break;
564 : 0 : default:
565 : 0 : PMD_DRV_LOG(ERR, "AES cipher key length is illegal!");
566 : 0 : return -EINVAL;
567 : : }
568 : :
569 : : return 0;
570 : : }
571 : :
572 : : /* Map rte_security_session_conf aead algo to NFP aead algo */
573 : : static int
574 : 0 : nfp_aead_map(struct rte_eth_dev *eth_dev,
575 : : struct rte_crypto_aead_xform *aead,
576 : : uint32_t key_length,
577 : : struct ipsec_add_sa *cfg)
578 : : {
579 : : int ret;
580 : : uint32_t i;
581 : : uint32_t index;
582 : : uint16_t iv_len;
583 : : uint32_t offset;
584 : : uint32_t device_id;
585 : : const char *iv_str;
586 : : const uint32_t *key;
587 : : struct nfp_net_hw *net_hw;
588 : :
589 : 0 : net_hw = eth_dev->data->dev_private;
590 : 0 : device_id = net_hw->device_id;
591 : : offset = 0;
592 : :
593 [ # # # ]: 0 : switch (aead->algo) {
594 : 0 : case RTE_CRYPTO_AEAD_AES_GCM:
595 [ # # ]: 0 : if (aead->digest_length != 16) {
596 : 0 : PMD_DRV_LOG(ERR, "ICV must be 128bit with RTE_CRYPTO_AEAD_AES_GCM!");
597 : 0 : return -EINVAL;
598 : : }
599 : :
600 : 0 : cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CTR;
601 : 0 : cfg->ctrl_word.hash = NFP_IPSEC_HASH_GF128_128;
602 : :
603 : 0 : ret = set_aes_keylen(key_length, cfg);
604 [ # # ]: 0 : if (ret < 0) {
605 : 0 : PMD_DRV_LOG(ERR, "Failed to set AES_GCM key length!");
606 : 0 : return -EINVAL;
607 : : }
608 : :
609 : : break;
610 : 0 : case RTE_CRYPTO_AEAD_CHACHA20_POLY1305:
611 [ # # ]: 0 : if (device_id != PCI_DEVICE_ID_NFP3800_PF_NIC) {
612 : 0 : PMD_DRV_LOG(ERR, "Unsupported aead CHACHA20_POLY1305 algorithm!");
613 : 0 : return -EINVAL;
614 : : }
615 : :
616 [ # # ]: 0 : if (aead->digest_length != 16) {
617 : 0 : PMD_DRV_LOG(ERR, "ICV must be 128bit with RTE_CRYPTO_AEAD_CHACHA20_POLY1305");
618 : 0 : return -EINVAL;
619 : : }
620 : :
621 : : /* Aead->alg_key_len includes 32-bit salt */
622 [ # # ]: 0 : if (key_length != 32) {
623 : 0 : PMD_DRV_LOG(ERR, "Unsupported CHACHA20 key length");
624 : 0 : return -EINVAL;
625 : : }
626 : :
627 : : /* The CHACHA20's mode is not configured */
628 : 0 : cfg->ctrl_word.hash = NFP_IPSEC_HASH_POLY1305_128;
629 : 0 : cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_CHACHA20;
630 : 0 : break;
631 : 0 : default:
632 : 0 : PMD_DRV_LOG(ERR, "Unsupported aead algorithm!");
633 : 0 : return -EINVAL;
634 : : }
635 : :
636 : 0 : key = (const uint32_t *)(aead->key.data);
637 : :
638 : : /*
639 : : * The CHACHA20's key order needs to be adjusted based on hardware design.
640 : : * Unadjusted order: {K0, K1, K2, K3, K4, K5, K6, K7}
641 : : * Adjusted order: {K4, K5, K6, K7, K0, K1, K2, K3}
642 : : */
643 [ # # ]: 0 : if (aead->algo == RTE_CRYPTO_AEAD_CHACHA20_POLY1305)
644 : 0 : offset = key_length / sizeof(cfg->cipher_key[0]) << 1;
645 : :
646 [ # # ]: 0 : for (i = 0; i < key_length / sizeof(cfg->cipher_key[0]); i++) {
647 : 0 : index = (i + offset) % (key_length / sizeof(cfg->cipher_key[0]));
648 : 0 : cfg->cipher_key[index] = rte_cpu_to_be_32(*key++);
649 : : }
650 : :
651 : : /*
652 : : * The iv of the FW is equal to ESN by default. Reading the
653 : : * iv of the configuration information is not supported.
654 : : */
655 : 0 : iv_str = getenv("ETH_SEC_IV_OVR");
656 [ # # ]: 0 : if (iv_str != NULL) {
657 : 0 : iv_len = aead->iv.length;
658 : 0 : nfp_aesgcm_iv_update(cfg, iv_len, iv_str);
659 : : }
660 : :
661 : : return 0;
662 : : }
663 : :
664 : : /* Map rte_security_session_conf cipher algo to NFP cipher algo */
665 : : static int
666 : 0 : nfp_cipher_map(struct rte_eth_dev *eth_dev,
667 : : struct rte_crypto_cipher_xform *cipher,
668 : : uint32_t key_length,
669 : : struct ipsec_add_sa *cfg)
670 : : {
671 : : int ret;
672 : : uint32_t i;
673 : : uint32_t device_id;
674 : : const uint32_t *key;
675 : : struct nfp_net_hw *net_hw;
676 : :
677 : 0 : net_hw = eth_dev->data->dev_private;
678 : 0 : device_id = net_hw->device_id;
679 : :
680 [ # # # # ]: 0 : switch (cipher->algo) {
681 : 0 : case RTE_CRYPTO_CIPHER_NULL:
682 : 0 : cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CBC;
683 : 0 : cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_NULL;
684 : 0 : break;
685 : 0 : case RTE_CRYPTO_CIPHER_3DES_CBC:
686 [ # # ]: 0 : if (device_id == PCI_DEVICE_ID_NFP3800_PF_NIC) {
687 : 0 : PMD_DRV_LOG(ERR, "Unsupported 3DESCBC encryption algorithm!");
688 : 0 : return -EINVAL;
689 : : }
690 : :
691 : 0 : cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CBC;
692 : 0 : cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_3DES;
693 : 0 : break;
694 : 0 : case RTE_CRYPTO_CIPHER_AES_CBC:
695 : 0 : cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CBC;
696 : 0 : ret = set_aes_keylen(key_length, cfg);
697 [ # # ]: 0 : if (ret < 0) {
698 : 0 : PMD_DRV_LOG(ERR, "Failed to set cipher key length!");
699 : 0 : return -EINVAL;
700 : : }
701 : :
702 : : break;
703 : 0 : default:
704 : 0 : PMD_DRV_LOG(ERR, "Unsupported cipher alg!");
705 : 0 : return -EINVAL;
706 : : }
707 : :
708 : 0 : key = (const uint32_t *)(cipher->key.data);
709 [ # # ]: 0 : if (key_length > sizeof(cfg->cipher_key)) {
710 : 0 : PMD_DRV_LOG(ERR, "Insufficient space for offloaded key");
711 : 0 : return -EINVAL;
712 : : }
713 : :
714 [ # # ]: 0 : for (i = 0; i < key_length / sizeof(cfg->cipher_key[0]); i++)
715 : 0 : cfg->cipher_key[i] = rte_cpu_to_be_32(*key++);
716 : :
717 : : return 0;
718 : : }
719 : :
720 : : static void
721 : : set_md5hmac(struct ipsec_add_sa *cfg,
722 : : uint32_t *digest_length)
723 : : {
724 [ # # # ]: 0 : switch (*digest_length) {
725 : 0 : case 96:
726 : 0 : cfg->ctrl_word.hash = NFP_IPSEC_HASH_MD5_96;
727 : 0 : break;
728 : 0 : case 128:
729 : 0 : cfg->ctrl_word.hash = NFP_IPSEC_HASH_MD5_128;
730 : 0 : break;
731 : : default:
732 : : *digest_length = 0;
733 : : }
734 : : }
735 : :
736 : : static void
737 : : set_sha1hmac(struct ipsec_add_sa *cfg,
738 : : uint32_t *digest_length)
739 : : {
740 [ # # # ]: 0 : switch (*digest_length) {
741 : 0 : case 96:
742 : 0 : cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA1_96;
743 : 0 : break;
744 : 0 : case 80:
745 : 0 : cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA1_80;
746 : 0 : break;
747 : : default:
748 : : *digest_length = 0;
749 : : }
750 : : }
751 : :
752 : : static void
753 : : set_sha2_256hmac(struct ipsec_add_sa *cfg,
754 : : uint32_t *digest_length)
755 : : {
756 [ # # # ]: 0 : switch (*digest_length) {
757 : 0 : case 96:
758 : 0 : cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA256_96;
759 : 0 : break;
760 : 0 : case 128:
761 : 0 : cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA256_128;
762 : 0 : break;
763 : : default:
764 : : *digest_length = 0;
765 : : }
766 : : }
767 : :
768 : : static void
769 : : set_sha2_384hmac(struct ipsec_add_sa *cfg,
770 : : uint32_t *digest_length)
771 : : {
772 [ # # # ]: 0 : switch (*digest_length) {
773 : 0 : case 96:
774 : 0 : cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA384_96;
775 : 0 : break;
776 : 0 : case 192:
777 : 0 : cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA384_192;
778 : 0 : break;
779 : : default:
780 : : *digest_length = 0;
781 : : }
782 : : }
783 : :
784 : : static void
785 : : set_sha2_512hmac(struct ipsec_add_sa *cfg,
786 : : uint32_t *digest_length)
787 : : {
788 [ # # # ]: 0 : switch (*digest_length) {
789 : 0 : case 96:
790 : 0 : cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA512_96;
791 : 0 : break;
792 : 0 : case 256:
793 : 0 : cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA512_256;
794 : 0 : break;
795 : : default:
796 : : *digest_length = 0;
797 : : }
798 : : }
799 : :
800 : : /* Map rte_security_session_conf auth algo to NFP auth algo */
801 : : static int
802 : 0 : nfp_auth_map(struct rte_eth_dev *eth_dev,
803 : : struct rte_crypto_auth_xform *auth,
804 : : uint32_t digest_length,
805 : : struct ipsec_add_sa *cfg)
806 : : {
807 : : uint32_t i;
808 : : uint8_t key_length;
809 : : uint32_t device_id;
810 : : const uint32_t *key;
811 : : struct nfp_net_hw *net_hw;
812 : :
813 [ # # ]: 0 : if (digest_length == 0) {
814 : 0 : PMD_DRV_LOG(ERR, "Auth digest length is illegal!");
815 : 0 : return -EINVAL;
816 : : }
817 : :
818 : 0 : net_hw = eth_dev->data->dev_private;
819 : 0 : device_id = net_hw->device_id;
820 : 0 : digest_length = digest_length << 3;
821 : :
822 [ # # # # : 0 : switch (auth->algo) {
# # # ]
823 : 0 : case RTE_CRYPTO_AUTH_NULL:
824 : 0 : cfg->ctrl_word.hash = NFP_IPSEC_HASH_NONE;
825 : : digest_length = 1;
826 : : break;
827 : 0 : case RTE_CRYPTO_AUTH_MD5_HMAC:
828 [ # # ]: 0 : if (device_id == PCI_DEVICE_ID_NFP3800_PF_NIC) {
829 : 0 : PMD_DRV_LOG(ERR, "Unsupported MD5HMAC authentication algorithm!");
830 : 0 : return -EINVAL;
831 : : }
832 : :
833 : : set_md5hmac(cfg, &digest_length);
834 : : break;
835 : : case RTE_CRYPTO_AUTH_SHA1_HMAC:
836 : : set_sha1hmac(cfg, &digest_length);
837 : : break;
838 : : case RTE_CRYPTO_AUTH_SHA256_HMAC:
839 : : set_sha2_256hmac(cfg, &digest_length);
840 : : break;
841 : : case RTE_CRYPTO_AUTH_SHA384_HMAC:
842 : : set_sha2_384hmac(cfg, &digest_length);
843 : : break;
844 : : case RTE_CRYPTO_AUTH_SHA512_HMAC:
845 : : set_sha2_512hmac(cfg, &digest_length);
846 : : break;
847 : 0 : default:
848 : 0 : PMD_DRV_LOG(ERR, "Unsupported auth alg!");
849 : 0 : return -EINVAL;
850 : : }
851 : :
852 : : if (digest_length == 0) {
853 : 0 : PMD_DRV_LOG(ERR, "Unsupported authentication algorithm digest length");
854 : 0 : return -EINVAL;
855 : : }
856 : :
857 : 0 : key = (const uint32_t *)(auth->key.data);
858 : 0 : key_length = auth->key.length;
859 [ # # ]: 0 : if (key_length > sizeof(cfg->auth_key)) {
860 : 0 : PMD_DRV_LOG(ERR, "Insufficient space for offloaded auth key!");
861 : 0 : return -EINVAL;
862 : : }
863 : :
864 [ # # ]: 0 : for (i = 0; i < key_length / sizeof(cfg->auth_key[0]); i++)
865 : 0 : cfg->auth_key[i] = rte_cpu_to_be_32(*key++);
866 : :
867 : : return 0;
868 : : }
869 : :
870 : : static int
871 : 0 : nfp_crypto_msg_build(struct rte_eth_dev *eth_dev,
872 : : struct rte_security_session_conf *conf,
873 : : struct nfp_ipsec_msg *msg)
874 : : {
875 : : int ret;
876 : : struct ipsec_add_sa *cfg;
877 : : struct rte_crypto_sym_xform *cur;
878 : : struct rte_crypto_sym_xform *next;
879 : : enum rte_security_ipsec_sa_direction direction;
880 : :
881 : 0 : cur = conf->crypto_xform;
882 [ # # ]: 0 : if (cur == NULL) {
883 : 0 : PMD_DRV_LOG(ERR, "Unsupported crypto_xform is NULL!");
884 : 0 : return -EINVAL;
885 : : }
886 : :
887 : 0 : next = cur->next;
888 : 0 : direction = conf->ipsec.direction;
889 : 0 : cfg = &msg->cfg_add_sa;
890 : :
891 [ # # # # ]: 0 : switch (cur->type) {
892 : 0 : case RTE_CRYPTO_SYM_XFORM_AEAD:
893 : : /* Aead transforms can be used for either inbound/outbound IPsec SAs */
894 [ # # ]: 0 : if (next != NULL) {
895 : 0 : PMD_DRV_LOG(ERR, "Next crypto_xform type should be NULL!");
896 : 0 : return -EINVAL;
897 : : }
898 : :
899 : 0 : ret = nfp_aead_map(eth_dev, &cur->aead, cur->aead.key.length, cfg);
900 [ # # ]: 0 : if (ret < 0) {
901 : 0 : PMD_DRV_LOG(ERR, "Failed to map aead alg!");
902 : 0 : return ret;
903 : : }
904 : :
905 [ # # ]: 0 : cfg->aesgcm_fields.salt = rte_cpu_to_be_32(conf->ipsec.salt);
906 : 0 : break;
907 : 0 : case RTE_CRYPTO_SYM_XFORM_AUTH:
908 : : /* Only support Auth + Cipher for inbound */
909 [ # # ]: 0 : if (direction != RTE_SECURITY_IPSEC_SA_DIR_INGRESS) {
910 : 0 : PMD_DRV_LOG(ERR, "Direction should be INGRESS, but it is not!");
911 : 0 : return -EINVAL;
912 : : }
913 : :
914 [ # # # # ]: 0 : if (next == NULL || next->type != RTE_CRYPTO_SYM_XFORM_CIPHER) {
915 : 0 : PMD_DRV_LOG(ERR, "Next crypto_xfrm should be cipher, but it is not!");
916 : 0 : return -EINVAL;
917 : : }
918 : :
919 : 0 : ret = nfp_auth_map(eth_dev, &cur->auth, cur->auth.digest_length, cfg);
920 [ # # ]: 0 : if (ret < 0) {
921 : 0 : PMD_DRV_LOG(ERR, "Failed to map auth alg!");
922 : 0 : return ret;
923 : : }
924 : :
925 : 0 : ret = nfp_cipher_map(eth_dev, &next->cipher, next->cipher.key.length, cfg);
926 [ # # ]: 0 : if (ret < 0) {
927 : 0 : PMD_DRV_LOG(ERR, "Failed to map cipher alg!");
928 : 0 : return ret;
929 : : }
930 : :
931 : : break;
932 : 0 : case RTE_CRYPTO_SYM_XFORM_CIPHER:
933 : : /* Only support Cipher + Auth for outbound */
934 [ # # ]: 0 : if (direction != RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
935 : 0 : PMD_DRV_LOG(ERR, "Direction should be EGRESS, but it is not!");
936 : 0 : return -EINVAL;
937 : : }
938 : :
939 [ # # # # ]: 0 : if (next == NULL || next->type != RTE_CRYPTO_SYM_XFORM_AUTH) {
940 : 0 : PMD_DRV_LOG(ERR, "Next crypto_xfrm should be auth, but it is not!");
941 : 0 : return -EINVAL;
942 : : }
943 : :
944 : 0 : ret = nfp_cipher_map(eth_dev, &cur->cipher, cur->cipher.key.length, cfg);
945 [ # # ]: 0 : if (ret < 0) {
946 : 0 : PMD_DRV_LOG(ERR, "Failed to map cipher alg!");
947 : 0 : return ret;
948 : : }
949 : :
950 : 0 : ret = nfp_auth_map(eth_dev, &next->auth, next->auth.digest_length, cfg);
951 [ # # ]: 0 : if (ret < 0) {
952 : 0 : PMD_DRV_LOG(ERR, "Failed to map auth alg!");
953 : 0 : return ret;
954 : : }
955 : :
956 : : break;
957 : 0 : default:
958 : 0 : PMD_DRV_LOG(ERR, "Unsupported crypto_xform type!");
959 : 0 : return -EINVAL;
960 : : }
961 : :
962 : : return 0;
963 : : }
964 : :
965 : : static int
966 : 0 : nfp_ipsec_msg_build(struct rte_eth_dev *eth_dev,
967 : : struct rte_security_session_conf *conf,
968 : : struct nfp_ipsec_msg *msg)
969 : : {
970 : : int ret;
971 : : struct ipsec_add_sa *cfg;
972 : : enum rte_security_ipsec_tunnel_type type;
973 : :
974 : : cfg = &msg->cfg_add_sa;
975 : 0 : cfg->spi = conf->ipsec.spi;
976 : 0 : cfg->pmtu_limit = 0xffff;
977 : :
978 : : /*
979 : : * UDP encapsulation
980 : : *
981 : : * 1: Do UDP encapsulation/decapsulation
982 : : * 0: No UDP encapsulation
983 : : */
984 [ # # ]: 0 : if (conf->ipsec.options.udp_encap == 1) {
985 : 0 : cfg->udp_enable = 1;
986 : 0 : cfg->natt_dst_port = NFP_UDP_ESP_PORT;
987 : 0 : cfg->natt_src_port = NFP_UDP_ESP_PORT;
988 : : }
989 : :
990 [ # # ]: 0 : if (conf->ipsec.options.copy_df == 1)
991 : 0 : cfg->df_ctrl = NFP_IPSEC_DF_COPY;
992 [ # # ]: 0 : else if (conf->ipsec.tunnel.ipv4.df != 0)
993 : 0 : cfg->df_ctrl = NFP_IPSEC_DF_SET;
994 : : else
995 : 0 : cfg->df_ctrl = NFP_IPSEC_DF_CLEAR;
996 : :
997 [ # # # ]: 0 : switch (conf->action_type) {
998 : 0 : case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO:
999 : 0 : cfg->ctrl_word.encap_dsbl = 1;
1000 : 0 : break;
1001 : 0 : case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL:
1002 : 0 : cfg->ctrl_word.encap_dsbl = 0;
1003 : 0 : break;
1004 : 0 : default:
1005 : 0 : PMD_DRV_LOG(ERR, "Unsupported IPsec action for offload, action: %d",
1006 : : conf->action_type);
1007 : 0 : return -EINVAL;
1008 : : }
1009 : :
1010 [ # # # ]: 0 : switch (conf->ipsec.proto) {
1011 : 0 : case RTE_SECURITY_IPSEC_SA_PROTO_ESP:
1012 : 0 : cfg->ctrl_word.proto = NFP_IPSEC_PROTOCOL_ESP;
1013 : 0 : break;
1014 : 0 : case RTE_SECURITY_IPSEC_SA_PROTO_AH:
1015 : 0 : cfg->ctrl_word.proto = NFP_IPSEC_PROTOCOL_AH;
1016 : 0 : break;
1017 : 0 : default:
1018 : 0 : PMD_DRV_LOG(ERR, "Unsupported IPsec protocol for offload, protocol: %d",
1019 : : conf->ipsec.proto);
1020 : 0 : return -EINVAL;
1021 : : }
1022 : :
1023 [ # # # ]: 0 : switch (conf->ipsec.mode) {
1024 : 0 : case RTE_SECURITY_IPSEC_SA_MODE_TUNNEL:
1025 : 0 : type = conf->ipsec.tunnel.type;
1026 : 0 : cfg->ctrl_word.mode = NFP_IPSEC_MODE_TUNNEL;
1027 [ # # ]: 0 : if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV4) {
1028 : 0 : cfg->src_ip.v4 = conf->ipsec.tunnel.ipv4.src_ip;
1029 : 0 : cfg->dst_ip.v4 = conf->ipsec.tunnel.ipv4.dst_ip;
1030 : 0 : cfg->ipv6 = 0;
1031 [ # # ]: 0 : } else if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV6) {
1032 : 0 : cfg->src_ip.v6 = conf->ipsec.tunnel.ipv6.src_addr;
1033 : 0 : cfg->dst_ip.v6 = conf->ipsec.tunnel.ipv6.dst_addr;
1034 : 0 : cfg->ipv6 = 1;
1035 : : } else {
1036 : 0 : PMD_DRV_LOG(ERR, "Unsupported address family!");
1037 : 0 : return -EINVAL;
1038 : : }
1039 : :
1040 : : break;
1041 : 0 : case RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT:
1042 : 0 : type = conf->ipsec.tunnel.type;
1043 : 0 : cfg->ctrl_word.mode = NFP_IPSEC_MODE_TRANSPORT;
1044 [ # # ]: 0 : if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV4) {
1045 : 0 : memset(&cfg->src_ip, 0, sizeof(cfg->src_ip));
1046 : 0 : cfg->ipv6 = 0;
1047 [ # # ]: 0 : } else if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV6) {
1048 : 0 : memset(&cfg->src_ip, 0, sizeof(cfg->src_ip));
1049 : 0 : cfg->ipv6 = 1;
1050 : : } else {
1051 : 0 : PMD_DRV_LOG(ERR, "Unsupported address family!");
1052 : 0 : return -EINVAL;
1053 : : }
1054 : :
1055 : : break;
1056 : 0 : default:
1057 : 0 : PMD_DRV_LOG(ERR, "Unsupported IPsec mode for offload, mode: %d",
1058 : : conf->ipsec.mode);
1059 : 0 : return -EINVAL;
1060 : : }
1061 : :
1062 : 0 : ret = nfp_crypto_msg_build(eth_dev, conf, msg);
1063 [ # # ]: 0 : if (ret < 0) {
1064 : 0 : PMD_DRV_LOG(ERR, "Failed to build auth/crypto/aead msg!");
1065 : 0 : return ret;
1066 : : }
1067 : :
1068 : : return 0;
1069 : : }
1070 : :
1071 : : static int
1072 : 0 : nfp_crypto_create_session(void *device,
1073 : : struct rte_security_session_conf *conf,
1074 : : struct rte_security_session *session)
1075 : : {
1076 : : int ret;
1077 : : int sa_idx;
1078 : : struct nfp_net_hw *net_hw;
1079 : : struct nfp_ipsec_msg msg;
1080 : : struct rte_eth_dev *eth_dev;
1081 : : struct nfp_ipsec_session *priv_session;
1082 : :
1083 : : /* Only support IPsec at present */
1084 [ # # ]: 0 : if (conf->protocol != RTE_SECURITY_PROTOCOL_IPSEC) {
1085 : 0 : PMD_DRV_LOG(ERR, "Unsupported non-IPsec offload!");
1086 : 0 : return -EINVAL;
1087 : : }
1088 : :
1089 : : sa_idx = -1;
1090 : : eth_dev = device;
1091 : 0 : priv_session = SECURITY_GET_SESS_PRIV(session);
1092 : 0 : net_hw = eth_dev->data->dev_private;
1093 : :
1094 [ # # ]: 0 : if (net_hw->ipsec_data->sa_free_cnt == 0) {
1095 : 0 : PMD_DRV_LOG(ERR, "No space in SA table, spi: %d", conf->ipsec.spi);
1096 : 0 : return -EINVAL;
1097 : : }
1098 : :
1099 : : nfp_get_sa_entry(net_hw->ipsec_data, &sa_idx);
1100 : :
1101 [ # # ]: 0 : if (sa_idx < 0) {
1102 : 0 : PMD_DRV_LOG(ERR, "Failed to get SA entry!");
1103 : 0 : return -EINVAL;
1104 : : }
1105 : :
1106 : : memset(&msg, 0, sizeof(msg));
1107 : 0 : ret = nfp_ipsec_msg_build(eth_dev, conf, &msg);
1108 [ # # ]: 0 : if (ret < 0) {
1109 : 0 : PMD_DRV_LOG(ERR, "Failed to build IPsec msg!");
1110 : 0 : return -EINVAL;
1111 : : }
1112 : :
1113 : 0 : msg.cmd = NFP_IPSEC_CFG_MSG_ADD_SA;
1114 : 0 : msg.sa_idx = sa_idx;
1115 : 0 : ret = nfp_ipsec_cfg_cmd_issue(net_hw, &msg);
1116 [ # # ]: 0 : if (ret < 0) {
1117 : 0 : PMD_DRV_LOG(ERR, "Failed to add SA to nic");
1118 : 0 : return -EINVAL;
1119 : : }
1120 : :
1121 : 0 : priv_session->action = conf->action_type;
1122 : 0 : priv_session->ipsec = conf->ipsec;
1123 : 0 : priv_session->msg = msg.cfg_add_sa;
1124 : 0 : priv_session->sa_index = sa_idx;
1125 : 0 : priv_session->dev = eth_dev;
1126 : 0 : priv_session->user_data = conf->userdata;
1127 : :
1128 : 0 : net_hw->ipsec_data->sa_free_cnt--;
1129 : 0 : net_hw->ipsec_data->sa_entries[sa_idx] = priv_session;
1130 : :
1131 : 0 : return 0;
1132 : : }
1133 : :
1134 : : static int
1135 : 0 : nfp_crypto_update_session(void *device __rte_unused,
1136 : : struct rte_security_session *session,
1137 : : struct rte_security_session_conf *conf)
1138 : : {
1139 : : struct nfp_ipsec_session *priv_session;
1140 : :
1141 : : priv_session = SECURITY_GET_SESS_PRIV(session);
1142 : : if (priv_session == NULL)
1143 : : return -EINVAL;
1144 : :
1145 : : /* Update IPsec ESN value */
1146 [ # # # # ]: 0 : if (priv_session->msg.ctrl_word.ext_seq != 0 && conf->ipsec.options.esn != 0) {
1147 : : /*
1148 : : * Store in nfp_ipsec_session for outbound SA for use
1149 : : * in nfp_security_set_pkt_metadata() function.
1150 : : */
1151 : 0 : priv_session->ipsec.esn.hi = conf->ipsec.esn.hi;
1152 : 0 : priv_session->ipsec.esn.low = conf->ipsec.esn.low;
1153 : : }
1154 : :
1155 : : return 0;
1156 : : }
1157 : :
1158 : : static int
1159 : 0 : nfp_security_set_pkt_metadata(void *device,
1160 : : struct rte_security_session *session,
1161 : : struct rte_mbuf *m,
1162 : : void *params)
1163 : : {
1164 : : int offset;
1165 : : uint64_t *sqn;
1166 : : struct nfp_net_hw *net_hw;
1167 : : struct rte_eth_dev *eth_dev;
1168 : : struct nfp_ipsec_session *priv_session;
1169 : :
1170 : : sqn = params;
1171 : : eth_dev = device;
1172 : : priv_session = SECURITY_GET_SESS_PRIV(session);
1173 : 0 : net_hw = eth_dev->data->dev_private;
1174 : :
1175 [ # # ]: 0 : if (priv_session->ipsec.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
1176 : : struct nfp_tx_ipsec_desc_msg *desc_md;
1177 : :
1178 : 0 : offset = net_hw->ipsec_data->pkt_dynfield_offset;
1179 : 0 : desc_md = RTE_MBUF_DYNFIELD(m, offset, struct nfp_tx_ipsec_desc_msg *);
1180 : :
1181 [ # # # # ]: 0 : if (priv_session->msg.ctrl_word.ext_seq != 0 && sqn != NULL) {
1182 [ # # ]: 0 : desc_md->esn.low = rte_cpu_to_be_32(*sqn);
1183 [ # # ]: 0 : desc_md->esn.hi = rte_cpu_to_be_32(*sqn >> 32);
1184 [ # # ]: 0 : } else if (priv_session->msg.ctrl_word.ext_seq != 0) {
1185 [ # # ]: 0 : desc_md->esn.low = rte_cpu_to_be_32(priv_session->ipsec.esn.low);
1186 [ # # ]: 0 : desc_md->esn.hi = rte_cpu_to_be_32(priv_session->ipsec.esn.hi);
1187 : : } else {
1188 [ # # ]: 0 : desc_md->esn.low = rte_cpu_to_be_32(priv_session->ipsec.esn.value);
1189 : 0 : desc_md->esn.hi = 0;
1190 : : }
1191 : :
1192 : 0 : desc_md->enc = 1;
1193 [ # # ]: 0 : desc_md->sa_idx = rte_cpu_to_be_32(priv_session->sa_index);
1194 : : }
1195 : :
1196 : 0 : return 0;
1197 : : }
1198 : :
1199 : : /**
1200 : : * Get discards packet statistics for each SA
1201 : : *
1202 : : * The sa_discard_stats contains the statistics of discards packets
1203 : : * of an SA. This function calculates the sum total of discarded packets.
1204 : : *
1205 : : * @param errors
1206 : : * The value is SA discards packet sum total
1207 : : * @param sa_discard_stats
1208 : : * The struct is SA discards packet Statistics
1209 : : */
1210 : : static void
1211 : : nfp_get_errorstats(uint64_t *errors,
1212 : : struct ipsec_discard_stats *sa_discard_stats)
1213 : : {
1214 : : uint32_t i;
1215 : : uint32_t len;
1216 : : uint32_t *perror;
1217 : :
1218 : : perror = &sa_discard_stats->discards_auth;
1219 : : len = sizeof(struct ipsec_discard_stats) / sizeof(uint32_t);
1220 : :
1221 [ # # # # ]: 0 : for (i = 0; i < len; i++)
1222 : 0 : *errors += *perror++;
1223 : :
1224 : 0 : *errors -= sa_discard_stats->ipv4_id_counter;
1225 : 0 : }
1226 : :
1227 : : static int
1228 : 0 : nfp_security_session_get_stats(void *device,
1229 : : struct rte_security_session *session,
1230 : : struct rte_security_stats *stats)
1231 : : {
1232 : : int ret;
1233 : : struct nfp_net_hw *net_hw;
1234 : : struct nfp_ipsec_msg msg;
1235 : : struct rte_eth_dev *eth_dev;
1236 : : struct ipsec_get_sa_stats *cfg_s;
1237 : : struct rte_security_ipsec_stats *ips_s;
1238 : : struct nfp_ipsec_session *priv_session;
1239 : : enum rte_security_ipsec_sa_direction direction;
1240 : :
1241 : : eth_dev = device;
1242 : : priv_session = SECURITY_GET_SESS_PRIV(session);
1243 : : memset(&msg, 0, sizeof(msg));
1244 : 0 : msg.cmd = NFP_IPSEC_CFG_MSG_GET_SA_STATS;
1245 : 0 : msg.sa_idx = priv_session->sa_index;
1246 : 0 : net_hw = eth_dev->data->dev_private;
1247 : :
1248 : 0 : ret = nfp_ipsec_cfg_cmd_issue(net_hw, &msg);
1249 [ # # ]: 0 : if (ret < 0) {
1250 : 0 : PMD_DRV_LOG(ERR, "Failed to get SA stats");
1251 : 0 : return ret;
1252 : : }
1253 : :
1254 : : cfg_s = &msg.cfg_get_stats;
1255 [ # # ]: 0 : direction = priv_session->ipsec.direction;
1256 : : memset(stats, 0, sizeof(struct rte_security_stats)); /* Start with zeros */
1257 : 0 : stats->protocol = RTE_SECURITY_PROTOCOL_IPSEC;
1258 : : ips_s = &stats->ipsec;
1259 : :
1260 : : /* Only display SA if any counters are non-zero */
1261 [ # # # # ]: 0 : if (cfg_s->lifetime_byte_count != 0 || cfg_s->pkt_count != 0) {
1262 [ # # ]: 0 : if (direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) {
1263 : 0 : ips_s->ipackets = cfg_s->pkt_count;
1264 : 0 : ips_s->ibytes = cfg_s->lifetime_byte_count;
1265 : : nfp_get_errorstats(&ips_s->ierrors, &cfg_s->sa_discard_stats);
1266 : : } else {
1267 : 0 : ips_s->opackets = cfg_s->pkt_count;
1268 : 0 : ips_s->obytes = cfg_s->lifetime_byte_count;
1269 : : nfp_get_errorstats(&ips_s->oerrors, &cfg_s->sa_discard_stats);
1270 : : }
1271 : : }
1272 : :
1273 : : return 0;
1274 : : }
1275 : :
1276 : : static const struct rte_security_capability *
1277 : 0 : nfp_crypto_capabilities_get(void *device __rte_unused)
1278 : : {
1279 : 0 : return nfp_security_caps;
1280 : : }
1281 : :
1282 : : static uint32_t
1283 : 0 : nfp_security_session_get_size(void *device __rte_unused)
1284 : : {
1285 : 0 : return sizeof(struct nfp_ipsec_session);
1286 : : }
1287 : :
1288 : : static int
1289 : 0 : nfp_crypto_remove_sa(struct rte_eth_dev *eth_dev,
1290 : : struct nfp_ipsec_session *priv_session)
1291 : : {
1292 : : int ret;
1293 : : uint32_t sa_index;
1294 : : struct nfp_net_hw *net_hw;
1295 : : struct nfp_ipsec_msg cfg;
1296 : :
1297 : 0 : sa_index = priv_session->sa_index;
1298 : 0 : net_hw = eth_dev->data->dev_private;
1299 : :
1300 : 0 : cfg.cmd = NFP_IPSEC_CFG_MSG_INV_SA;
1301 : 0 : cfg.sa_idx = sa_index;
1302 : 0 : ret = nfp_ipsec_cfg_cmd_issue(net_hw, &cfg);
1303 [ # # ]: 0 : if (ret < 0) {
1304 : 0 : PMD_DRV_LOG(ERR, "Failed to remove SA!");
1305 : 0 : return -EINVAL;
1306 : : }
1307 : :
1308 : 0 : net_hw->ipsec_data->sa_free_cnt++;
1309 : 0 : net_hw->ipsec_data->sa_entries[sa_index] = NULL;
1310 : :
1311 : 0 : return 0;
1312 : : }
1313 : :
1314 : : static int
1315 : 0 : nfp_crypto_remove_session(void *device,
1316 : : struct rte_security_session *session)
1317 : : {
1318 : : int ret;
1319 : : struct rte_eth_dev *eth_dev;
1320 : : struct nfp_ipsec_session *priv_session;
1321 : :
1322 : : eth_dev = device;
1323 : 0 : priv_session = SECURITY_GET_SESS_PRIV(session);
1324 [ # # ]: 0 : if (eth_dev != priv_session->dev) {
1325 : 0 : PMD_DRV_LOG(ERR, "Session not bound to this device");
1326 : 0 : return -ENODEV;
1327 : : }
1328 : :
1329 : 0 : ret = nfp_crypto_remove_sa(eth_dev, priv_session);
1330 [ # # ]: 0 : if (ret < 0) {
1331 : 0 : PMD_DRV_LOG(ERR, "Failed to remove session");
1332 : 0 : return -EFAULT;
1333 : : }
1334 : :
1335 : : memset(priv_session, 0, sizeof(struct nfp_ipsec_session));
1336 : :
1337 : 0 : return 0;
1338 : : }
1339 : :
1340 : : static const struct rte_security_ops nfp_security_ops = {
1341 : : .session_create = nfp_crypto_create_session,
1342 : : .session_update = nfp_crypto_update_session,
1343 : : .session_get_size = nfp_security_session_get_size,
1344 : : .session_stats_get = nfp_security_session_get_stats,
1345 : : .session_destroy = nfp_crypto_remove_session,
1346 : : .set_pkt_metadata = nfp_security_set_pkt_metadata,
1347 : : .capabilities_get = nfp_crypto_capabilities_get,
1348 : : };
1349 : :
1350 : : static int
1351 : 0 : nfp_ipsec_ctx_create(struct rte_eth_dev *dev,
1352 : : struct nfp_net_ipsec_data *data)
1353 : : {
1354 : : struct rte_security_ctx *ctx;
1355 : : static const struct rte_mbuf_dynfield pkt_md_dynfield = {
1356 : : .name = "nfp_ipsec_crypto_pkt_metadata",
1357 : : .size = sizeof(struct nfp_tx_ipsec_desc_msg),
1358 : : .align = alignof(struct nfp_tx_ipsec_desc_msg),
1359 : : };
1360 : :
1361 : 0 : ctx = rte_zmalloc("security_ctx",
1362 : : sizeof(struct rte_security_ctx), 0);
1363 [ # # ]: 0 : if (ctx == NULL) {
1364 : 0 : PMD_INIT_LOG(ERR, "Failed to malloc security_ctx");
1365 : 0 : return -ENOMEM;
1366 : : }
1367 : :
1368 : 0 : ctx->device = dev;
1369 : 0 : ctx->ops = &nfp_security_ops;
1370 : 0 : ctx->sess_cnt = 0;
1371 : 0 : dev->security_ctx = ctx;
1372 : :
1373 : 0 : data->pkt_dynfield_offset = rte_mbuf_dynfield_register(&pkt_md_dynfield);
1374 [ # # ]: 0 : if (data->pkt_dynfield_offset < 0) {
1375 : 0 : PMD_INIT_LOG(ERR, "Failed to register mbuf esn_dynfield");
1376 : 0 : return -ENOMEM;
1377 : : }
1378 : :
1379 : : return 0;
1380 : : }
1381 : :
1382 : : int
1383 : 0 : nfp_ipsec_init(struct rte_eth_dev *dev)
1384 : : {
1385 : : int ret;
1386 : : uint32_t cap_extend;
1387 : : struct nfp_net_hw *net_hw;
1388 : : struct nfp_net_ipsec_data *data;
1389 : :
1390 : 0 : net_hw = dev->data->dev_private;
1391 : :
1392 : 0 : cap_extend = net_hw->super.cap_ext;
1393 [ # # ]: 0 : if ((cap_extend & NFP_NET_CFG_CTRL_IPSEC) == 0) {
1394 : 0 : PMD_INIT_LOG(INFO, "Unsupported IPsec extend capability");
1395 : 0 : return 0;
1396 : : }
1397 : :
1398 : 0 : data = rte_zmalloc("ipsec_data", sizeof(struct nfp_net_ipsec_data), 0);
1399 [ # # ]: 0 : if (data == NULL) {
1400 : 0 : PMD_INIT_LOG(ERR, "Failed to malloc ipsec_data");
1401 : 0 : return -ENOMEM;
1402 : : }
1403 : :
1404 : 0 : data->pkt_dynfield_offset = -1;
1405 : 0 : data->sa_free_cnt = NFP_NET_IPSEC_MAX_SA_CNT;
1406 : 0 : net_hw->ipsec_data = data;
1407 : :
1408 : 0 : ret = nfp_ipsec_ctx_create(dev, data);
1409 [ # # ]: 0 : if (ret != 0) {
1410 : 0 : PMD_INIT_LOG(ERR, "Failed to create IPsec ctx");
1411 : 0 : goto ipsec_cleanup;
1412 : : }
1413 : :
1414 : : return 0;
1415 : :
1416 : : ipsec_cleanup:
1417 : 0 : nfp_ipsec_uninit(dev);
1418 : :
1419 : 0 : return ret;
1420 : : }
1421 : :
1422 : : static void
1423 : : nfp_ipsec_ctx_destroy(struct rte_eth_dev *dev)
1424 : : {
1425 : 0 : rte_free(dev->security_ctx);
1426 : : }
1427 : :
1428 : : void
1429 : 0 : nfp_ipsec_uninit(struct rte_eth_dev *dev)
1430 : : {
1431 : : uint16_t i;
1432 : : uint32_t cap_extend;
1433 : : struct nfp_net_hw *net_hw;
1434 : : struct nfp_ipsec_session *priv_session;
1435 : :
1436 : 0 : net_hw = dev->data->dev_private;
1437 : :
1438 : 0 : cap_extend = net_hw->super.cap_ext;
1439 [ # # ]: 0 : if ((cap_extend & NFP_NET_CFG_CTRL_IPSEC) == 0) {
1440 : 0 : PMD_INIT_LOG(INFO, "Unsupported IPsec extend capability");
1441 : 0 : return;
1442 : : }
1443 : :
1444 : : nfp_ipsec_ctx_destroy(dev);
1445 : :
1446 [ # # ]: 0 : if (net_hw->ipsec_data == NULL) {
1447 : 0 : PMD_INIT_LOG(INFO, "IPsec data is NULL!");
1448 : 0 : return;
1449 : : }
1450 : :
1451 [ # # ]: 0 : for (i = 0; i < NFP_NET_IPSEC_MAX_SA_CNT; i++) {
1452 : 0 : priv_session = net_hw->ipsec_data->sa_entries[i];
1453 [ # # ]: 0 : if (priv_session != NULL)
1454 : : memset(priv_session, 0, sizeof(struct nfp_ipsec_session));
1455 : : }
1456 : :
1457 : 0 : rte_free(net_hw->ipsec_data);
1458 : : }
1459 : :
|