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