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