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 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 msg->rsp = NFP_IPSEC_CFG_MSG_OK; 448 449 for (i = 0; i < msg_size; i++) 450 nn_cfg_writel(&net_hw->super, NFP_NET_CFG_MBOX_VAL + 4 * i, msg->raw[i]); 451 452 ret = nfp_net_mbox_reconfig(net_hw, NFP_NET_CFG_MBOX_CMD_IPSEC); 453 if (ret < 0) { 454 PMD_DRV_LOG(ERR, "Failed to IPsec reconfig mbox"); 455 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 for (i = 0; i < msg_size; i++) 464 msg->raw[i] = nn_cfg_readl(&net_hw->super, NFP_NET_CFG_MBOX_VAL + 4 * i); 465 466 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 for (i = 0; i < NFP_NET_IPSEC_MAX_SA_CNT; i++) { 510 if (data->sa_entries[i] == NULL) { 511 *sa_idx = i; 512 break; 513 } 514 } 515 } 516 517 static void 518 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 iv_str = strdup(iv_string); 529 cfg_iv = (uint8_t *)cfg->aesgcm_fields.iv; 530 531 for (i = 0; i < iv_len; i++) { 532 iv_b = strtok_r(i ? NULL : iv_str, ",", &save); 533 if (iv_b == NULL) 534 break; 535 536 cfg_iv[i] = strtoul(iv_b, NULL, 0); 537 } 538 539 *(uint32_t *)cfg_iv = rte_be_to_cpu_32(*(uint32_t *)cfg_iv); 540 *(uint32_t *)&cfg_iv[4] = rte_be_to_cpu_32(*(uint32_t *)&cfg_iv[4]); 541 542 free(iv_str); 543 } 544 545 static int 546 set_aes_keylen(uint32_t key_length, 547 struct ipsec_add_sa *cfg) 548 { 549 switch (key_length << 3) { 550 case 128: 551 cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_AES128; 552 break; 553 case 192: 554 cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_AES192; 555 break; 556 case 256: 557 cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_AES256; 558 break; 559 default: 560 PMD_DRV_LOG(ERR, "AES cipher key length is illegal!"); 561 return -EINVAL; 562 } 563 564 return 0; 565 } 566 567 /* Map rte_security_session_conf aead algo to NFP aead algo */ 568 static int 569 nfp_aead_map(struct rte_eth_dev *eth_dev, 570 struct rte_crypto_aead_xform *aead, 571 uint32_t key_length, 572 struct ipsec_add_sa *cfg) 573 { 574 int ret; 575 uint32_t i; 576 uint32_t index; 577 uint16_t iv_len; 578 uint32_t offset; 579 uint32_t device_id; 580 const char *iv_str; 581 const uint32_t *key; 582 struct nfp_net_hw *net_hw; 583 584 net_hw = eth_dev->data->dev_private; 585 device_id = net_hw->device_id; 586 offset = 0; 587 588 switch (aead->algo) { 589 case RTE_CRYPTO_AEAD_AES_GCM: 590 if (aead->digest_length != 16) { 591 PMD_DRV_LOG(ERR, "ICV must be 128bit with RTE_CRYPTO_AEAD_AES_GCM!"); 592 return -EINVAL; 593 } 594 595 cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CTR; 596 cfg->ctrl_word.hash = NFP_IPSEC_HASH_GF128_128; 597 598 ret = set_aes_keylen(key_length, cfg); 599 if (ret < 0) { 600 PMD_DRV_LOG(ERR, "Failed to set AES_GCM key length!"); 601 return -EINVAL; 602 } 603 604 break; 605 case RTE_CRYPTO_AEAD_CHACHA20_POLY1305: 606 if (device_id != PCI_DEVICE_ID_NFP3800_PF_NIC) { 607 PMD_DRV_LOG(ERR, "Unsupported aead CHACHA20_POLY1305 algorithm!"); 608 return -EINVAL; 609 } 610 611 if (aead->digest_length != 16) { 612 PMD_DRV_LOG(ERR, "ICV must be 128bit with RTE_CRYPTO_AEAD_CHACHA20_POLY1305"); 613 return -EINVAL; 614 } 615 616 /* Aead->alg_key_len includes 32-bit salt */ 617 if (key_length != 32) { 618 PMD_DRV_LOG(ERR, "Unsupported CHACHA20 key length"); 619 return -EINVAL; 620 } 621 622 /* The CHACHA20's mode is not configured */ 623 cfg->ctrl_word.hash = NFP_IPSEC_HASH_POLY1305_128; 624 cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_CHACHA20; 625 break; 626 default: 627 PMD_DRV_LOG(ERR, "Unsupported aead algorithm!"); 628 return -EINVAL; 629 } 630 631 key = (const uint32_t *)(aead->key.data); 632 633 /* 634 * The CHACHA20's key order needs to be adjusted based on hardware design. 635 * Unadjusted order: {K0, K1, K2, K3, K4, K5, K6, K7} 636 * Adjusted order: {K4, K5, K6, K7, K0, K1, K2, K3} 637 */ 638 if (aead->algo == RTE_CRYPTO_AEAD_CHACHA20_POLY1305) 639 offset = key_length / sizeof(cfg->cipher_key[0]) << 1; 640 641 for (i = 0; i < key_length / sizeof(cfg->cipher_key[0]); i++) { 642 index = (i + offset) % (key_length / sizeof(cfg->cipher_key[0])); 643 cfg->cipher_key[index] = rte_cpu_to_be_32(*key++); 644 } 645 646 /* 647 * The iv of the FW is equal to ESN by default. Reading the 648 * iv of the configuration information is not supported. 649 */ 650 iv_str = getenv("ETH_SEC_IV_OVR"); 651 if (iv_str != NULL) { 652 iv_len = aead->iv.length; 653 nfp_aesgcm_iv_update(cfg, iv_len, iv_str); 654 } 655 656 return 0; 657 } 658 659 /* Map rte_security_session_conf cipher algo to NFP cipher algo */ 660 static int 661 nfp_cipher_map(struct rte_eth_dev *eth_dev, 662 struct rte_crypto_cipher_xform *cipher, 663 uint32_t key_length, 664 struct ipsec_add_sa *cfg) 665 { 666 int ret; 667 uint32_t i; 668 uint32_t device_id; 669 const uint32_t *key; 670 struct nfp_net_hw *net_hw; 671 672 net_hw = eth_dev->data->dev_private; 673 device_id = net_hw->device_id; 674 675 switch (cipher->algo) { 676 case RTE_CRYPTO_CIPHER_NULL: 677 cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CBC; 678 cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_NULL; 679 break; 680 case RTE_CRYPTO_CIPHER_3DES_CBC: 681 if (device_id == PCI_DEVICE_ID_NFP3800_PF_NIC) { 682 PMD_DRV_LOG(ERR, "Unsupported 3DESCBC encryption algorithm!"); 683 return -EINVAL; 684 } 685 686 cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CBC; 687 cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_3DES; 688 break; 689 case RTE_CRYPTO_CIPHER_AES_CBC: 690 cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CBC; 691 ret = set_aes_keylen(key_length, cfg); 692 if (ret < 0) { 693 PMD_DRV_LOG(ERR, "Failed to set cipher key length!"); 694 return -EINVAL; 695 } 696 697 break; 698 default: 699 PMD_DRV_LOG(ERR, "Unsupported cipher alg!"); 700 return -EINVAL; 701 } 702 703 key = (const uint32_t *)(cipher->key.data); 704 if (key_length > sizeof(cfg->cipher_key)) { 705 PMD_DRV_LOG(ERR, "Insufficient space for offloaded key"); 706 return -EINVAL; 707 } 708 709 for (i = 0; i < key_length / sizeof(cfg->cipher_key[0]); i++) 710 cfg->cipher_key[i] = rte_cpu_to_be_32(*key++); 711 712 return 0; 713 } 714 715 static void 716 set_md5hmac(struct ipsec_add_sa *cfg, 717 uint32_t *digest_length) 718 { 719 switch (*digest_length) { 720 case 96: 721 cfg->ctrl_word.hash = NFP_IPSEC_HASH_MD5_96; 722 break; 723 case 128: 724 cfg->ctrl_word.hash = NFP_IPSEC_HASH_MD5_128; 725 break; 726 default: 727 *digest_length = 0; 728 } 729 } 730 731 static void 732 set_sha1hmac(struct ipsec_add_sa *cfg, 733 uint32_t *digest_length) 734 { 735 switch (*digest_length) { 736 case 96: 737 cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA1_96; 738 break; 739 case 80: 740 cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA1_80; 741 break; 742 default: 743 *digest_length = 0; 744 } 745 } 746 747 static void 748 set_sha2_256hmac(struct ipsec_add_sa *cfg, 749 uint32_t *digest_length) 750 { 751 switch (*digest_length) { 752 case 96: 753 cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA256_96; 754 break; 755 case 128: 756 cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA256_128; 757 break; 758 default: 759 *digest_length = 0; 760 } 761 } 762 763 static void 764 set_sha2_384hmac(struct ipsec_add_sa *cfg, 765 uint32_t *digest_length) 766 { 767 switch (*digest_length) { 768 case 96: 769 cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA384_96; 770 break; 771 case 192: 772 cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA384_192; 773 break; 774 default: 775 *digest_length = 0; 776 } 777 } 778 779 static void 780 set_sha2_512hmac(struct ipsec_add_sa *cfg, 781 uint32_t *digest_length) 782 { 783 switch (*digest_length) { 784 case 96: 785 cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA512_96; 786 break; 787 case 256: 788 cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA512_256; 789 break; 790 default: 791 *digest_length = 0; 792 } 793 } 794 795 /* Map rte_security_session_conf auth algo to NFP auth algo */ 796 static int 797 nfp_auth_map(struct rte_eth_dev *eth_dev, 798 struct rte_crypto_auth_xform *auth, 799 uint32_t digest_length, 800 struct ipsec_add_sa *cfg) 801 { 802 uint32_t i; 803 uint8_t key_length; 804 uint32_t device_id; 805 const uint32_t *key; 806 struct nfp_net_hw *net_hw; 807 808 if (digest_length == 0) { 809 PMD_DRV_LOG(ERR, "Auth digest length is illegal!"); 810 return -EINVAL; 811 } 812 813 net_hw = eth_dev->data->dev_private; 814 device_id = net_hw->device_id; 815 digest_length = digest_length << 3; 816 817 switch (auth->algo) { 818 case RTE_CRYPTO_AUTH_NULL: 819 cfg->ctrl_word.hash = NFP_IPSEC_HASH_NONE; 820 digest_length = 1; 821 break; 822 case RTE_CRYPTO_AUTH_MD5_HMAC: 823 if (device_id == PCI_DEVICE_ID_NFP3800_PF_NIC) { 824 PMD_DRV_LOG(ERR, "Unsupported MD5HMAC authentication algorithm!"); 825 return -EINVAL; 826 } 827 828 set_md5hmac(cfg, &digest_length); 829 break; 830 case RTE_CRYPTO_AUTH_SHA1_HMAC: 831 set_sha1hmac(cfg, &digest_length); 832 break; 833 case RTE_CRYPTO_AUTH_SHA256_HMAC: 834 set_sha2_256hmac(cfg, &digest_length); 835 break; 836 case RTE_CRYPTO_AUTH_SHA384_HMAC: 837 set_sha2_384hmac(cfg, &digest_length); 838 break; 839 case RTE_CRYPTO_AUTH_SHA512_HMAC: 840 set_sha2_512hmac(cfg, &digest_length); 841 break; 842 default: 843 PMD_DRV_LOG(ERR, "Unsupported auth alg!"); 844 return -EINVAL; 845 } 846 847 if (digest_length == 0) { 848 PMD_DRV_LOG(ERR, "Unsupported authentication algorithm digest length"); 849 return -EINVAL; 850 } 851 852 key = (const uint32_t *)(auth->key.data); 853 key_length = auth->key.length; 854 if (key_length > sizeof(cfg->auth_key)) { 855 PMD_DRV_LOG(ERR, "Insufficient space for offloaded auth key!"); 856 return -EINVAL; 857 } 858 859 for (i = 0; i < key_length / sizeof(cfg->auth_key[0]); i++) 860 cfg->auth_key[i] = rte_cpu_to_be_32(*key++); 861 862 return 0; 863 } 864 865 static int 866 nfp_crypto_msg_build(struct rte_eth_dev *eth_dev, 867 struct rte_security_session_conf *conf, 868 struct nfp_ipsec_msg *msg) 869 { 870 int ret; 871 struct ipsec_add_sa *cfg; 872 struct rte_crypto_sym_xform *cur; 873 struct rte_crypto_sym_xform *next; 874 enum rte_security_ipsec_sa_direction direction; 875 876 cur = conf->crypto_xform; 877 if (cur == NULL) { 878 PMD_DRV_LOG(ERR, "Unsupported crypto_xform is NULL!"); 879 return -EINVAL; 880 } 881 882 next = cur->next; 883 direction = conf->ipsec.direction; 884 cfg = &msg->cfg_add_sa; 885 886 switch (cur->type) { 887 case RTE_CRYPTO_SYM_XFORM_AEAD: 888 /* Aead transforms can be used for either inbound/outbound IPsec SAs */ 889 if (next != NULL) { 890 PMD_DRV_LOG(ERR, "Next crypto_xform type should be NULL!"); 891 return -EINVAL; 892 } 893 894 ret = nfp_aead_map(eth_dev, &cur->aead, cur->aead.key.length, cfg); 895 if (ret < 0) { 896 PMD_DRV_LOG(ERR, "Failed to map aead alg!"); 897 return ret; 898 } 899 900 cfg->aesgcm_fields.salt = rte_cpu_to_be_32(conf->ipsec.salt); 901 break; 902 case RTE_CRYPTO_SYM_XFORM_AUTH: 903 /* Only support Auth + Cipher for inbound */ 904 if (direction != RTE_SECURITY_IPSEC_SA_DIR_INGRESS) { 905 PMD_DRV_LOG(ERR, "Direction should be INGRESS, but it is not!"); 906 return -EINVAL; 907 } 908 909 if (next == NULL || next->type != RTE_CRYPTO_SYM_XFORM_CIPHER) { 910 PMD_DRV_LOG(ERR, "Next crypto_xfrm should be cipher, but it is not!"); 911 return -EINVAL; 912 } 913 914 ret = nfp_auth_map(eth_dev, &cur->auth, cur->auth.digest_length, cfg); 915 if (ret < 0) { 916 PMD_DRV_LOG(ERR, "Failed to map auth alg!"); 917 return ret; 918 } 919 920 ret = nfp_cipher_map(eth_dev, &next->cipher, next->cipher.key.length, cfg); 921 if (ret < 0) { 922 PMD_DRV_LOG(ERR, "Failed to map cipher alg!"); 923 return ret; 924 } 925 926 break; 927 case RTE_CRYPTO_SYM_XFORM_CIPHER: 928 /* Only support Cipher + Auth for outbound */ 929 if (direction != RTE_SECURITY_IPSEC_SA_DIR_EGRESS) { 930 PMD_DRV_LOG(ERR, "Direction should be EGRESS, but it is not!"); 931 return -EINVAL; 932 } 933 934 if (next == NULL || next->type != RTE_CRYPTO_SYM_XFORM_AUTH) { 935 PMD_DRV_LOG(ERR, "Next crypto_xfrm should be auth, but it is not!"); 936 return -EINVAL; 937 } 938 939 ret = nfp_cipher_map(eth_dev, &cur->cipher, cur->cipher.key.length, cfg); 940 if (ret < 0) { 941 PMD_DRV_LOG(ERR, "Failed to map cipher alg!"); 942 return ret; 943 } 944 945 ret = nfp_auth_map(eth_dev, &next->auth, next->auth.digest_length, cfg); 946 if (ret < 0) { 947 PMD_DRV_LOG(ERR, "Failed to map auth alg!"); 948 return ret; 949 } 950 951 break; 952 default: 953 PMD_DRV_LOG(ERR, "Unsupported crypto_xform type!"); 954 return -EINVAL; 955 } 956 957 return 0; 958 } 959 960 static int 961 nfp_ipsec_msg_build(struct rte_eth_dev *eth_dev, 962 struct rte_security_session_conf *conf, 963 struct nfp_ipsec_msg *msg) 964 { 965 int ret; 966 struct ipsec_add_sa *cfg; 967 enum rte_security_ipsec_tunnel_type type; 968 969 cfg = &msg->cfg_add_sa; 970 cfg->spi = conf->ipsec.spi; 971 cfg->pmtu_limit = 0xffff; 972 973 /* 974 * UDP encapsulation 975 * 976 * 1: Do UDP encapsulation/decapsulation 977 * 0: No UDP encapsulation 978 */ 979 if (conf->ipsec.options.udp_encap == 1) { 980 cfg->udp_enable = 1; 981 cfg->natt_dst_port = NFP_UDP_ESP_PORT; 982 cfg->natt_src_port = NFP_UDP_ESP_PORT; 983 } 984 985 if (conf->ipsec.options.copy_df == 1) 986 cfg->df_ctrl = NFP_IPSEC_DF_COPY; 987 else if (conf->ipsec.tunnel.ipv4.df != 0) 988 cfg->df_ctrl = NFP_IPSEC_DF_SET; 989 else 990 cfg->df_ctrl = NFP_IPSEC_DF_CLEAR; 991 992 switch (conf->action_type) { 993 case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO: 994 cfg->ctrl_word.encap_dsbl = 1; 995 break; 996 case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL: 997 cfg->ctrl_word.encap_dsbl = 0; 998 break; 999 default: 1000 PMD_DRV_LOG(ERR, "Unsupported IPsec action for offload, action: %d", 1001 conf->action_type); 1002 return -EINVAL; 1003 } 1004 1005 switch (conf->ipsec.proto) { 1006 case RTE_SECURITY_IPSEC_SA_PROTO_ESP: 1007 cfg->ctrl_word.proto = NFP_IPSEC_PROTOCOL_ESP; 1008 break; 1009 case RTE_SECURITY_IPSEC_SA_PROTO_AH: 1010 cfg->ctrl_word.proto = NFP_IPSEC_PROTOCOL_AH; 1011 break; 1012 default: 1013 PMD_DRV_LOG(ERR, "Unsupported IPsec protocol for offload, protocol: %d", 1014 conf->ipsec.proto); 1015 return -EINVAL; 1016 } 1017 1018 switch (conf->ipsec.mode) { 1019 case RTE_SECURITY_IPSEC_SA_MODE_TUNNEL: 1020 type = conf->ipsec.tunnel.type; 1021 cfg->ctrl_word.mode = NFP_IPSEC_MODE_TUNNEL; 1022 if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV4) { 1023 cfg->src_ip.v4 = conf->ipsec.tunnel.ipv4.src_ip; 1024 cfg->dst_ip.v4 = conf->ipsec.tunnel.ipv4.dst_ip; 1025 cfg->ipv6 = 0; 1026 } else if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV6) { 1027 cfg->src_ip.v6 = conf->ipsec.tunnel.ipv6.src_addr; 1028 cfg->dst_ip.v6 = conf->ipsec.tunnel.ipv6.dst_addr; 1029 cfg->ipv6 = 1; 1030 } else { 1031 PMD_DRV_LOG(ERR, "Unsupported address family!"); 1032 return -EINVAL; 1033 } 1034 1035 break; 1036 case RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT: 1037 type = conf->ipsec.tunnel.type; 1038 cfg->ctrl_word.mode = NFP_IPSEC_MODE_TRANSPORT; 1039 if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV4) { 1040 memset(&cfg->src_ip, 0, sizeof(cfg->src_ip)); 1041 cfg->ipv6 = 0; 1042 } else if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV6) { 1043 memset(&cfg->src_ip, 0, sizeof(cfg->src_ip)); 1044 cfg->ipv6 = 1; 1045 } else { 1046 PMD_DRV_LOG(ERR, "Unsupported address family!"); 1047 return -EINVAL; 1048 } 1049 1050 break; 1051 default: 1052 PMD_DRV_LOG(ERR, "Unsupported IPsec mode for offload, mode: %d", 1053 conf->ipsec.mode); 1054 return -EINVAL; 1055 } 1056 1057 ret = nfp_crypto_msg_build(eth_dev, conf, msg); 1058 if (ret < 0) { 1059 PMD_DRV_LOG(ERR, "Failed to build auth/crypto/aead msg!"); 1060 return ret; 1061 } 1062 1063 return 0; 1064 } 1065 1066 static int 1067 nfp_crypto_create_session(void *device, 1068 struct rte_security_session_conf *conf, 1069 struct rte_security_session *session) 1070 { 1071 int ret; 1072 int sa_idx; 1073 struct nfp_net_hw *net_hw; 1074 struct nfp_ipsec_msg msg; 1075 struct rte_eth_dev *eth_dev; 1076 struct nfp_ipsec_session *priv_session; 1077 1078 /* Only support IPsec at present */ 1079 if (conf->protocol != RTE_SECURITY_PROTOCOL_IPSEC) { 1080 PMD_DRV_LOG(ERR, "Unsupported non-IPsec offload!"); 1081 return -EINVAL; 1082 } 1083 1084 sa_idx = -1; 1085 eth_dev = device; 1086 priv_session = SECURITY_GET_SESS_PRIV(session); 1087 net_hw = eth_dev->data->dev_private; 1088 1089 if (net_hw->ipsec_data->sa_free_cnt == 0) { 1090 PMD_DRV_LOG(ERR, "No space in SA table, spi: %d", conf->ipsec.spi); 1091 return -EINVAL; 1092 } 1093 1094 nfp_get_sa_entry(net_hw->ipsec_data, &sa_idx); 1095 1096 if (sa_idx < 0) { 1097 PMD_DRV_LOG(ERR, "Failed to get SA entry!"); 1098 return -EINVAL; 1099 } 1100 1101 memset(&msg, 0, sizeof(msg)); 1102 ret = nfp_ipsec_msg_build(eth_dev, conf, &msg); 1103 if (ret < 0) { 1104 PMD_DRV_LOG(ERR, "Failed to build IPsec msg!"); 1105 return -EINVAL; 1106 } 1107 1108 msg.cmd = NFP_IPSEC_CFG_MSG_ADD_SA; 1109 msg.sa_idx = sa_idx; 1110 ret = nfp_ipsec_cfg_cmd_issue(net_hw, &msg); 1111 if (ret < 0) { 1112 PMD_DRV_LOG(ERR, "Failed to add SA to nic"); 1113 return -EINVAL; 1114 } 1115 1116 priv_session->action = conf->action_type; 1117 priv_session->ipsec = conf->ipsec; 1118 priv_session->msg = msg.cfg_add_sa; 1119 priv_session->sa_index = sa_idx; 1120 priv_session->dev = eth_dev; 1121 priv_session->user_data = conf->userdata; 1122 1123 net_hw->ipsec_data->sa_free_cnt--; 1124 net_hw->ipsec_data->sa_entries[sa_idx] = priv_session; 1125 1126 return 0; 1127 } 1128 1129 static int 1130 nfp_crypto_update_session(void *device __rte_unused, 1131 struct rte_security_session *session, 1132 struct rte_security_session_conf *conf) 1133 { 1134 struct nfp_ipsec_session *priv_session; 1135 1136 priv_session = SECURITY_GET_SESS_PRIV(session); 1137 if (priv_session == NULL) 1138 return -EINVAL; 1139 1140 /* Update IPsec ESN value */ 1141 if (priv_session->msg.ctrl_word.ext_seq != 0 && conf->ipsec.options.esn != 0) { 1142 /* 1143 * Store in nfp_ipsec_session for outbound SA for use 1144 * in nfp_security_set_pkt_metadata() function. 1145 */ 1146 priv_session->ipsec.esn.hi = conf->ipsec.esn.hi; 1147 priv_session->ipsec.esn.low = conf->ipsec.esn.low; 1148 } 1149 1150 return 0; 1151 } 1152 1153 static int 1154 nfp_security_set_pkt_metadata(void *device, 1155 struct rte_security_session *session, 1156 struct rte_mbuf *m, 1157 void *params) 1158 { 1159 int offset; 1160 uint64_t *sqn; 1161 struct nfp_net_hw *net_hw; 1162 struct rte_eth_dev *eth_dev; 1163 struct nfp_ipsec_session *priv_session; 1164 1165 sqn = params; 1166 eth_dev = device; 1167 priv_session = SECURITY_GET_SESS_PRIV(session); 1168 net_hw = eth_dev->data->dev_private; 1169 1170 if (priv_session->ipsec.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) { 1171 struct nfp_tx_ipsec_desc_msg *desc_md; 1172 1173 offset = net_hw->ipsec_data->pkt_dynfield_offset; 1174 desc_md = RTE_MBUF_DYNFIELD(m, offset, struct nfp_tx_ipsec_desc_msg *); 1175 1176 if (priv_session->msg.ctrl_word.ext_seq != 0 && sqn != NULL) { 1177 desc_md->esn.low = rte_cpu_to_be_32(*sqn); 1178 desc_md->esn.hi = rte_cpu_to_be_32(*sqn >> 32); 1179 } else if (priv_session->msg.ctrl_word.ext_seq != 0) { 1180 desc_md->esn.low = rte_cpu_to_be_32(priv_session->ipsec.esn.low); 1181 desc_md->esn.hi = rte_cpu_to_be_32(priv_session->ipsec.esn.hi); 1182 } else { 1183 desc_md->esn.low = rte_cpu_to_be_32(priv_session->ipsec.esn.value); 1184 desc_md->esn.hi = 0; 1185 } 1186 1187 desc_md->enc = 1; 1188 desc_md->sa_idx = rte_cpu_to_be_32(priv_session->sa_index); 1189 } 1190 1191 return 0; 1192 } 1193 1194 /** 1195 * Get discards packet statistics for each SA 1196 * 1197 * The sa_discard_stats contains the statistics of discards packets 1198 * of an SA. This function calculates the sum total of discarded packets. 1199 * 1200 * @param errors 1201 * The value is SA discards packet sum total 1202 * @param sa_discard_stats 1203 * The struct is SA discards packet Statistics 1204 */ 1205 static void 1206 nfp_get_errorstats(uint64_t *errors, 1207 struct ipsec_discard_stats *sa_discard_stats) 1208 { 1209 uint32_t i; 1210 uint32_t len; 1211 uint32_t *perror; 1212 1213 perror = &sa_discard_stats->discards_auth; 1214 len = sizeof(struct ipsec_discard_stats) / sizeof(uint32_t); 1215 1216 for (i = 0; i < len; i++) 1217 *errors += *perror++; 1218 1219 *errors -= sa_discard_stats->ipv4_id_counter; 1220 } 1221 1222 static int 1223 nfp_security_session_get_stats(void *device, 1224 struct rte_security_session *session, 1225 struct rte_security_stats *stats) 1226 { 1227 int ret; 1228 struct nfp_net_hw *net_hw; 1229 struct nfp_ipsec_msg msg; 1230 struct rte_eth_dev *eth_dev; 1231 struct ipsec_get_sa_stats *cfg_s; 1232 struct rte_security_ipsec_stats *ips_s; 1233 struct nfp_ipsec_session *priv_session; 1234 enum rte_security_ipsec_sa_direction direction; 1235 1236 eth_dev = device; 1237 priv_session = SECURITY_GET_SESS_PRIV(session); 1238 memset(&msg, 0, sizeof(msg)); 1239 msg.cmd = NFP_IPSEC_CFG_MSG_GET_SA_STATS; 1240 msg.sa_idx = priv_session->sa_index; 1241 net_hw = eth_dev->data->dev_private; 1242 1243 ret = nfp_ipsec_cfg_cmd_issue(net_hw, &msg); 1244 if (ret < 0) { 1245 PMD_DRV_LOG(ERR, "Failed to get SA stats"); 1246 return ret; 1247 } 1248 1249 cfg_s = &msg.cfg_get_stats; 1250 direction = priv_session->ipsec.direction; 1251 memset(stats, 0, sizeof(struct rte_security_stats)); /* Start with zeros */ 1252 stats->protocol = RTE_SECURITY_PROTOCOL_IPSEC; 1253 ips_s = &stats->ipsec; 1254 1255 /* Only display SA if any counters are non-zero */ 1256 if (cfg_s->lifetime_byte_count != 0 || cfg_s->pkt_count != 0) { 1257 if (direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) { 1258 ips_s->ipackets = cfg_s->pkt_count; 1259 ips_s->ibytes = cfg_s->lifetime_byte_count; 1260 nfp_get_errorstats(&ips_s->ierrors, &cfg_s->sa_discard_stats); 1261 } else { 1262 ips_s->opackets = cfg_s->pkt_count; 1263 ips_s->obytes = cfg_s->lifetime_byte_count; 1264 nfp_get_errorstats(&ips_s->oerrors, &cfg_s->sa_discard_stats); 1265 } 1266 } 1267 1268 return 0; 1269 } 1270 1271 static const struct rte_security_capability * 1272 nfp_crypto_capabilities_get(void *device __rte_unused) 1273 { 1274 return nfp_security_caps; 1275 } 1276 1277 static uint32_t 1278 nfp_security_session_get_size(void *device __rte_unused) 1279 { 1280 return sizeof(struct nfp_ipsec_session); 1281 } 1282 1283 static int 1284 nfp_crypto_remove_sa(struct rte_eth_dev *eth_dev, 1285 struct nfp_ipsec_session *priv_session) 1286 { 1287 int ret; 1288 uint32_t sa_index; 1289 struct nfp_net_hw *net_hw; 1290 struct nfp_ipsec_msg cfg; 1291 1292 sa_index = priv_session->sa_index; 1293 net_hw = eth_dev->data->dev_private; 1294 1295 cfg.cmd = NFP_IPSEC_CFG_MSG_INV_SA; 1296 cfg.sa_idx = sa_index; 1297 ret = nfp_ipsec_cfg_cmd_issue(net_hw, &cfg); 1298 if (ret < 0) { 1299 PMD_DRV_LOG(ERR, "Failed to remove SA!"); 1300 return -EINVAL; 1301 } 1302 1303 net_hw->ipsec_data->sa_free_cnt++; 1304 net_hw->ipsec_data->sa_entries[sa_index] = NULL; 1305 1306 return 0; 1307 } 1308 1309 static int 1310 nfp_crypto_remove_session(void *device, 1311 struct rte_security_session *session) 1312 { 1313 int ret; 1314 struct rte_eth_dev *eth_dev; 1315 struct nfp_ipsec_session *priv_session; 1316 1317 eth_dev = device; 1318 priv_session = SECURITY_GET_SESS_PRIV(session); 1319 if (eth_dev != priv_session->dev) { 1320 PMD_DRV_LOG(ERR, "Session not bound to this device"); 1321 return -ENODEV; 1322 } 1323 1324 ret = nfp_crypto_remove_sa(eth_dev, priv_session); 1325 if (ret < 0) { 1326 PMD_DRV_LOG(ERR, "Failed to remove session"); 1327 return -EFAULT; 1328 } 1329 1330 memset(priv_session, 0, sizeof(struct nfp_ipsec_session)); 1331 1332 return 0; 1333 } 1334 1335 static const struct rte_security_ops nfp_security_ops = { 1336 .session_create = nfp_crypto_create_session, 1337 .session_update = nfp_crypto_update_session, 1338 .session_get_size = nfp_security_session_get_size, 1339 .session_stats_get = nfp_security_session_get_stats, 1340 .session_destroy = nfp_crypto_remove_session, 1341 .set_pkt_metadata = nfp_security_set_pkt_metadata, 1342 .capabilities_get = nfp_crypto_capabilities_get, 1343 }; 1344 1345 static int 1346 nfp_ipsec_ctx_create(struct rte_eth_dev *dev, 1347 struct nfp_net_ipsec_data *data) 1348 { 1349 struct rte_security_ctx *ctx; 1350 static const struct rte_mbuf_dynfield pkt_md_dynfield = { 1351 .name = "nfp_ipsec_crypto_pkt_metadata", 1352 .size = sizeof(struct nfp_tx_ipsec_desc_msg), 1353 .align = alignof(struct nfp_tx_ipsec_desc_msg), 1354 }; 1355 1356 ctx = rte_zmalloc("security_ctx", 1357 sizeof(struct rte_security_ctx), 0); 1358 if (ctx == NULL) { 1359 PMD_INIT_LOG(ERR, "Failed to malloc security_ctx"); 1360 return -ENOMEM; 1361 } 1362 1363 ctx->device = dev; 1364 ctx->ops = &nfp_security_ops; 1365 ctx->sess_cnt = 0; 1366 dev->security_ctx = ctx; 1367 1368 data->pkt_dynfield_offset = rte_mbuf_dynfield_register(&pkt_md_dynfield); 1369 if (data->pkt_dynfield_offset < 0) { 1370 PMD_INIT_LOG(ERR, "Failed to register mbuf esn_dynfield"); 1371 return -ENOMEM; 1372 } 1373 1374 return 0; 1375 } 1376 1377 int 1378 nfp_ipsec_init(struct rte_eth_dev *dev) 1379 { 1380 int ret; 1381 uint32_t cap_extend; 1382 struct nfp_net_hw *net_hw; 1383 struct nfp_net_ipsec_data *data; 1384 1385 net_hw = dev->data->dev_private; 1386 1387 cap_extend = net_hw->super.cap_ext; 1388 if ((cap_extend & NFP_NET_CFG_CTRL_IPSEC) == 0) { 1389 PMD_INIT_LOG(INFO, "Unsupported IPsec extend capability"); 1390 return 0; 1391 } 1392 1393 data = rte_zmalloc("ipsec_data", sizeof(struct nfp_net_ipsec_data), 0); 1394 if (data == NULL) { 1395 PMD_INIT_LOG(ERR, "Failed to malloc ipsec_data"); 1396 return -ENOMEM; 1397 } 1398 1399 data->pkt_dynfield_offset = -1; 1400 data->sa_free_cnt = NFP_NET_IPSEC_MAX_SA_CNT; 1401 net_hw->ipsec_data = data; 1402 1403 ret = nfp_ipsec_ctx_create(dev, data); 1404 if (ret != 0) { 1405 PMD_INIT_LOG(ERR, "Failed to create IPsec ctx"); 1406 goto ipsec_cleanup; 1407 } 1408 1409 return 0; 1410 1411 ipsec_cleanup: 1412 nfp_ipsec_uninit(dev); 1413 1414 return ret; 1415 } 1416 1417 static void 1418 nfp_ipsec_ctx_destroy(struct rte_eth_dev *dev) 1419 { 1420 rte_free(dev->security_ctx); 1421 } 1422 1423 void 1424 nfp_ipsec_uninit(struct rte_eth_dev *dev) 1425 { 1426 uint16_t i; 1427 uint32_t cap_extend; 1428 struct nfp_net_hw *net_hw; 1429 struct nfp_ipsec_session *priv_session; 1430 1431 net_hw = dev->data->dev_private; 1432 1433 cap_extend = net_hw->super.cap_ext; 1434 if ((cap_extend & NFP_NET_CFG_CTRL_IPSEC) == 0) { 1435 PMD_INIT_LOG(INFO, "Unsupported IPsec extend capability"); 1436 return; 1437 } 1438 1439 nfp_ipsec_ctx_destroy(dev); 1440 1441 if (net_hw->ipsec_data == NULL) { 1442 PMD_INIT_LOG(INFO, "IPsec data is NULL!"); 1443 return; 1444 } 1445 1446 for (i = 0; i < NFP_NET_IPSEC_MAX_SA_CNT; i++) { 1447 priv_session = net_hw->ipsec_data->sa_entries[i]; 1448 if (priv_session != NULL) 1449 memset(priv_session, 0, sizeof(struct nfp_ipsec_session)); 1450 } 1451 1452 rte_free(net_hw->ipsec_data); 1453 } 1454 1455