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 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 msg->rsp = NFP_IPSEC_CFG_MSG_OK; 446 447 for (i = 0; i < msg_size; i++) 448 nn_cfg_writel(&net_hw->super, NFP_NET_CFG_MBOX_VAL + 4 * i, msg->raw[i]); 449 450 ret = nfp_net_mbox_reconfig(net_hw, NFP_NET_CFG_MBOX_CMD_IPSEC); 451 if (ret < 0) { 452 PMD_DRV_LOG(ERR, "Failed to IPsec reconfig mbox"); 453 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 for (i = 0; i < msg_size; i++) 462 msg->raw[i] = nn_cfg_readl(&net_hw->super, NFP_NET_CFG_MBOX_VAL + 4 * i); 463 464 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 for (i = 0; i < NFP_NET_IPSEC_MAX_SA_CNT; i++) { 508 if (data->sa_entries[i] == NULL) { 509 *sa_idx = i; 510 break; 511 } 512 } 513 } 514 515 static void 516 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 iv_str = strdup(iv_string); 527 cfg_iv = (uint8_t *)cfg->aesgcm_fields.iv; 528 529 for (i = 0; i < iv_len; i++) { 530 iv_b = strtok_r(i ? NULL : iv_str, ",", &save); 531 if (iv_b == NULL) 532 break; 533 534 cfg_iv[i] = strtoul(iv_b, NULL, 0); 535 } 536 537 *(uint32_t *)cfg_iv = rte_be_to_cpu_32(*(uint32_t *)cfg_iv); 538 *(uint32_t *)&cfg_iv[4] = rte_be_to_cpu_32(*(uint32_t *)&cfg_iv[4]); 539 540 free(iv_str); 541 } 542 543 static int 544 set_aes_keylen(uint32_t key_length, 545 struct ipsec_add_sa *cfg) 546 { 547 switch (key_length << 3) { 548 case 128: 549 cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_AES128; 550 break; 551 case 192: 552 cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_AES192; 553 break; 554 case 256: 555 cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_AES256; 556 break; 557 default: 558 PMD_DRV_LOG(ERR, "AES cipher key length is illegal!"); 559 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 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 net_hw = eth_dev->data->dev_private; 583 device_id = net_hw->device_id; 584 offset = 0; 585 586 switch (aead->algo) { 587 case RTE_CRYPTO_AEAD_AES_GCM: 588 if (aead->digest_length != 16) { 589 PMD_DRV_LOG(ERR, "ICV must be 128bit with RTE_CRYPTO_AEAD_AES_GCM!"); 590 return -EINVAL; 591 } 592 593 cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CTR; 594 cfg->ctrl_word.hash = NFP_IPSEC_HASH_GF128_128; 595 596 ret = set_aes_keylen(key_length, cfg); 597 if (ret < 0) { 598 PMD_DRV_LOG(ERR, "Failed to set AES_GCM key length!"); 599 return -EINVAL; 600 } 601 602 break; 603 case RTE_CRYPTO_AEAD_CHACHA20_POLY1305: 604 if (device_id != PCI_DEVICE_ID_NFP3800_PF_NIC) { 605 PMD_DRV_LOG(ERR, "Unsupported aead CHACHA20_POLY1305 algorithm!"); 606 return -EINVAL; 607 } 608 609 if (aead->digest_length != 16) { 610 PMD_DRV_LOG(ERR, "ICV must be 128bit with RTE_CRYPTO_AEAD_CHACHA20_POLY1305"); 611 return -EINVAL; 612 } 613 614 /* Aead->alg_key_len includes 32-bit salt */ 615 if (key_length != 32) { 616 PMD_DRV_LOG(ERR, "Unsupported CHACHA20 key length"); 617 return -EINVAL; 618 } 619 620 /* The CHACHA20's mode is not configured */ 621 cfg->ctrl_word.hash = NFP_IPSEC_HASH_POLY1305_128; 622 cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_CHACHA20; 623 break; 624 default: 625 PMD_DRV_LOG(ERR, "Unsupported aead algorithm!"); 626 return -EINVAL; 627 } 628 629 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 if (aead->algo == RTE_CRYPTO_AEAD_CHACHA20_POLY1305) 637 offset = key_length / sizeof(cfg->cipher_key[0]) << 1; 638 639 for (i = 0; i < key_length / sizeof(cfg->cipher_key[0]); i++) { 640 index = (i + offset) % (key_length / sizeof(cfg->cipher_key[0])); 641 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 iv_str = getenv("ETH_SEC_IV_OVR"); 649 if (iv_str != NULL) { 650 iv_len = aead->iv.length; 651 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 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 net_hw = eth_dev->data->dev_private; 671 device_id = net_hw->device_id; 672 673 switch (cipher->algo) { 674 case RTE_CRYPTO_CIPHER_NULL: 675 cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CBC; 676 cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_NULL; 677 break; 678 case RTE_CRYPTO_CIPHER_3DES_CBC: 679 if (device_id == PCI_DEVICE_ID_NFP3800_PF_NIC) { 680 PMD_DRV_LOG(ERR, "Unsupported 3DESCBC encryption algorithm!"); 681 return -EINVAL; 682 } 683 684 cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CBC; 685 cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_3DES; 686 break; 687 case RTE_CRYPTO_CIPHER_AES_CBC: 688 cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CBC; 689 ret = set_aes_keylen(key_length, cfg); 690 if (ret < 0) { 691 PMD_DRV_LOG(ERR, "Failed to set cipher key length!"); 692 return -EINVAL; 693 } 694 695 break; 696 default: 697 PMD_DRV_LOG(ERR, "Unsupported cipher alg!"); 698 return -EINVAL; 699 } 700 701 key = (const uint32_t *)(cipher->key.data); 702 if (key_length > sizeof(cfg->cipher_key)) { 703 PMD_DRV_LOG(ERR, "Insufficient space for offloaded key"); 704 return -EINVAL; 705 } 706 707 for (i = 0; i < key_length / sizeof(cfg->cipher_key[0]); i++) 708 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 switch (*digest_length) { 718 case 96: 719 cfg->ctrl_word.hash = NFP_IPSEC_HASH_MD5_96; 720 break; 721 case 128: 722 cfg->ctrl_word.hash = NFP_IPSEC_HASH_MD5_128; 723 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 switch (*digest_length) { 734 case 96: 735 cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA1_96; 736 break; 737 case 80: 738 cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA1_80; 739 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 switch (*digest_length) { 750 case 96: 751 cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA256_96; 752 break; 753 case 128: 754 cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA256_128; 755 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 switch (*digest_length) { 766 case 96: 767 cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA384_96; 768 break; 769 case 192: 770 cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA384_192; 771 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 switch (*digest_length) { 782 case 96: 783 cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA512_96; 784 break; 785 case 256: 786 cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA512_256; 787 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 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 if (digest_length == 0) { 807 PMD_DRV_LOG(ERR, "Auth digest length is illegal!"); 808 return -EINVAL; 809 } 810 811 net_hw = eth_dev->data->dev_private; 812 device_id = net_hw->device_id; 813 digest_length = digest_length << 3; 814 815 switch (auth->algo) { 816 case RTE_CRYPTO_AUTH_NULL: 817 cfg->ctrl_word.hash = NFP_IPSEC_HASH_NONE; 818 digest_length = 1; 819 break; 820 case RTE_CRYPTO_AUTH_MD5_HMAC: 821 if (device_id == PCI_DEVICE_ID_NFP3800_PF_NIC) { 822 PMD_DRV_LOG(ERR, "Unsupported MD5HMAC authentication algorithm!"); 823 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 default: 841 PMD_DRV_LOG(ERR, "Unsupported auth alg!"); 842 return -EINVAL; 843 } 844 845 if (digest_length == 0) { 846 PMD_DRV_LOG(ERR, "Unsupported authentication algorithm digest length"); 847 return -EINVAL; 848 } 849 850 key = (const uint32_t *)(auth->key.data); 851 key_length = auth->key.length; 852 if (key_length > sizeof(cfg->auth_key)) { 853 PMD_DRV_LOG(ERR, "Insufficient space for offloaded auth key!"); 854 return -EINVAL; 855 } 856 857 for (i = 0; i < key_length / sizeof(cfg->auth_key[0]); i++) 858 cfg->auth_key[i] = rte_cpu_to_be_32(*key++); 859 860 return 0; 861 } 862 863 static int 864 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 cur = conf->crypto_xform; 875 if (cur == NULL) { 876 PMD_DRV_LOG(ERR, "Unsupported crypto_xform is NULL!"); 877 return -EINVAL; 878 } 879 880 next = cur->next; 881 direction = conf->ipsec.direction; 882 cfg = &msg->cfg_add_sa; 883 884 switch (cur->type) { 885 case RTE_CRYPTO_SYM_XFORM_AEAD: 886 /* Aead transforms can be used for either inbound/outbound IPsec SAs */ 887 if (next != NULL) { 888 PMD_DRV_LOG(ERR, "Next crypto_xform type should be NULL!"); 889 return -EINVAL; 890 } 891 892 ret = nfp_aead_map(eth_dev, &cur->aead, cur->aead.key.length, cfg); 893 if (ret < 0) { 894 PMD_DRV_LOG(ERR, "Failed to map aead alg!"); 895 return ret; 896 } 897 898 cfg->aesgcm_fields.salt = rte_cpu_to_be_32(conf->ipsec.salt); 899 break; 900 case RTE_CRYPTO_SYM_XFORM_AUTH: 901 /* Only support Auth + Cipher for inbound */ 902 if (direction != RTE_SECURITY_IPSEC_SA_DIR_INGRESS) { 903 PMD_DRV_LOG(ERR, "Direction should be INGRESS, but it is not!"); 904 return -EINVAL; 905 } 906 907 if (next == NULL || next->type != RTE_CRYPTO_SYM_XFORM_CIPHER) { 908 PMD_DRV_LOG(ERR, "Next crypto_xfrm should be cipher, but it is not!"); 909 return -EINVAL; 910 } 911 912 ret = nfp_auth_map(eth_dev, &cur->auth, cur->auth.digest_length, cfg); 913 if (ret < 0) { 914 PMD_DRV_LOG(ERR, "Failed to map auth alg!"); 915 return ret; 916 } 917 918 ret = nfp_cipher_map(eth_dev, &next->cipher, next->cipher.key.length, cfg); 919 if (ret < 0) { 920 PMD_DRV_LOG(ERR, "Failed to map cipher alg!"); 921 return ret; 922 } 923 924 break; 925 case RTE_CRYPTO_SYM_XFORM_CIPHER: 926 /* Only support Cipher + Auth for outbound */ 927 if (direction != RTE_SECURITY_IPSEC_SA_DIR_EGRESS) { 928 PMD_DRV_LOG(ERR, "Direction should be EGRESS, but it is not!"); 929 return -EINVAL; 930 } 931 932 if (next == NULL || next->type != RTE_CRYPTO_SYM_XFORM_AUTH) { 933 PMD_DRV_LOG(ERR, "Next crypto_xfrm should be auth, but it is not!"); 934 return -EINVAL; 935 } 936 937 ret = nfp_cipher_map(eth_dev, &cur->cipher, cur->cipher.key.length, cfg); 938 if (ret < 0) { 939 PMD_DRV_LOG(ERR, "Failed to map cipher alg!"); 940 return ret; 941 } 942 943 ret = nfp_auth_map(eth_dev, &next->auth, next->auth.digest_length, cfg); 944 if (ret < 0) { 945 PMD_DRV_LOG(ERR, "Failed to map auth alg!"); 946 return ret; 947 } 948 949 break; 950 default: 951 PMD_DRV_LOG(ERR, "Unsupported crypto_xform type!"); 952 return -EINVAL; 953 } 954 955 return 0; 956 } 957 958 static int 959 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 cfg->spi = conf->ipsec.spi; 969 cfg->pmtu_limit = 0xffff; 970 971 /* 972 * UDP encapsulation 973 * 974 * 1: Do UDP encapsulation/decapsulation 975 * 0: No UDP encapsulation 976 */ 977 if (conf->ipsec.options.udp_encap == 1) { 978 cfg->udp_enable = 1; 979 cfg->natt_dst_port = NFP_UDP_ESP_PORT; 980 cfg->natt_src_port = NFP_UDP_ESP_PORT; 981 } 982 983 if (conf->ipsec.options.copy_df == 1) 984 cfg->df_ctrl = NFP_IPSEC_DF_COPY; 985 else if (conf->ipsec.tunnel.ipv4.df != 0) 986 cfg->df_ctrl = NFP_IPSEC_DF_SET; 987 else 988 cfg->df_ctrl = NFP_IPSEC_DF_CLEAR; 989 990 switch (conf->action_type) { 991 case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO: 992 cfg->ctrl_word.encap_dsbl = 1; 993 break; 994 case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL: 995 cfg->ctrl_word.encap_dsbl = 0; 996 break; 997 default: 998 PMD_DRV_LOG(ERR, "Unsupported IPsec action for offload, action: %d", 999 conf->action_type); 1000 return -EINVAL; 1001 } 1002 1003 switch (conf->ipsec.proto) { 1004 case RTE_SECURITY_IPSEC_SA_PROTO_ESP: 1005 cfg->ctrl_word.proto = NFP_IPSEC_PROTOCOL_ESP; 1006 break; 1007 case RTE_SECURITY_IPSEC_SA_PROTO_AH: 1008 cfg->ctrl_word.proto = NFP_IPSEC_PROTOCOL_AH; 1009 break; 1010 default: 1011 PMD_DRV_LOG(ERR, "Unsupported IPsec protocol for offload, protocol: %d", 1012 conf->ipsec.proto); 1013 return -EINVAL; 1014 } 1015 1016 switch (conf->ipsec.mode) { 1017 case RTE_SECURITY_IPSEC_SA_MODE_TUNNEL: 1018 type = conf->ipsec.tunnel.type; 1019 cfg->ctrl_word.mode = NFP_IPSEC_MODE_TUNNEL; 1020 if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV4) { 1021 cfg->src_ip.v4 = conf->ipsec.tunnel.ipv4.src_ip; 1022 cfg->dst_ip.v4 = conf->ipsec.tunnel.ipv4.dst_ip; 1023 cfg->ipv6 = 0; 1024 } else if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV6) { 1025 cfg->src_ip.v6 = conf->ipsec.tunnel.ipv6.src_addr; 1026 cfg->dst_ip.v6 = conf->ipsec.tunnel.ipv6.dst_addr; 1027 cfg->ipv6 = 1; 1028 } else { 1029 PMD_DRV_LOG(ERR, "Unsupported address family!"); 1030 return -EINVAL; 1031 } 1032 1033 break; 1034 case RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT: 1035 type = conf->ipsec.tunnel.type; 1036 cfg->ctrl_word.mode = NFP_IPSEC_MODE_TRANSPORT; 1037 if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV4) { 1038 memset(&cfg->src_ip, 0, sizeof(cfg->src_ip)); 1039 cfg->ipv6 = 0; 1040 } else if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV6) { 1041 memset(&cfg->src_ip, 0, sizeof(cfg->src_ip)); 1042 cfg->ipv6 = 1; 1043 } else { 1044 PMD_DRV_LOG(ERR, "Unsupported address family!"); 1045 return -EINVAL; 1046 } 1047 1048 break; 1049 default: 1050 PMD_DRV_LOG(ERR, "Unsupported IPsec mode for offload, mode: %d", 1051 conf->ipsec.mode); 1052 return -EINVAL; 1053 } 1054 1055 ret = nfp_crypto_msg_build(eth_dev, conf, msg); 1056 if (ret < 0) { 1057 PMD_DRV_LOG(ERR, "Failed to build auth/crypto/aead msg!"); 1058 return ret; 1059 } 1060 1061 return 0; 1062 } 1063 1064 static int 1065 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 if (conf->protocol != RTE_SECURITY_PROTOCOL_IPSEC) { 1078 PMD_DRV_LOG(ERR, "Unsupported non-IPsec offload!"); 1079 return -EINVAL; 1080 } 1081 1082 sa_idx = -1; 1083 eth_dev = device; 1084 priv_session = SECURITY_GET_SESS_PRIV(session); 1085 net_hw = eth_dev->data->dev_private; 1086 1087 if (net_hw->ipsec_data->sa_free_cnt == 0) { 1088 PMD_DRV_LOG(ERR, "No space in SA table, spi: %d", conf->ipsec.spi); 1089 return -EINVAL; 1090 } 1091 1092 nfp_get_sa_entry(net_hw->ipsec_data, &sa_idx); 1093 1094 if (sa_idx < 0) { 1095 PMD_DRV_LOG(ERR, "Failed to get SA entry!"); 1096 return -EINVAL; 1097 } 1098 1099 memset(&msg, 0, sizeof(msg)); 1100 ret = nfp_ipsec_msg_build(eth_dev, conf, &msg); 1101 if (ret < 0) { 1102 PMD_DRV_LOG(ERR, "Failed to build IPsec msg!"); 1103 return -EINVAL; 1104 } 1105 1106 msg.cmd = NFP_IPSEC_CFG_MSG_ADD_SA; 1107 msg.sa_idx = sa_idx; 1108 ret = nfp_ipsec_cfg_cmd_issue(net_hw, &msg); 1109 if (ret < 0) { 1110 PMD_DRV_LOG(ERR, "Failed to add SA to nic"); 1111 return -EINVAL; 1112 } 1113 1114 priv_session->action = conf->action_type; 1115 priv_session->ipsec = conf->ipsec; 1116 priv_session->msg = msg.cfg_add_sa; 1117 priv_session->sa_index = sa_idx; 1118 priv_session->dev = eth_dev; 1119 priv_session->user_data = conf->userdata; 1120 1121 net_hw->ipsec_data->sa_free_cnt--; 1122 net_hw->ipsec_data->sa_entries[sa_idx] = priv_session; 1123 1124 return 0; 1125 } 1126 1127 static int 1128 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 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 priv_session->ipsec.esn.hi = conf->ipsec.esn.hi; 1145 priv_session->ipsec.esn.low = conf->ipsec.esn.low; 1146 } 1147 1148 return 0; 1149 } 1150 1151 static int 1152 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 net_hw = eth_dev->data->dev_private; 1167 1168 if (priv_session->ipsec.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) { 1169 struct nfp_tx_ipsec_desc_msg *desc_md; 1170 1171 offset = net_hw->ipsec_data->pkt_dynfield_offset; 1172 desc_md = RTE_MBUF_DYNFIELD(m, offset, struct nfp_tx_ipsec_desc_msg *); 1173 1174 if (priv_session->msg.ctrl_word.ext_seq != 0 && sqn != NULL) { 1175 desc_md->esn.low = rte_cpu_to_be_32(*sqn); 1176 desc_md->esn.hi = rte_cpu_to_be_32(*sqn >> 32); 1177 } else if (priv_session->msg.ctrl_word.ext_seq != 0) { 1178 desc_md->esn.low = rte_cpu_to_be_32(priv_session->ipsec.esn.low); 1179 desc_md->esn.hi = rte_cpu_to_be_32(priv_session->ipsec.esn.hi); 1180 } else { 1181 desc_md->esn.low = rte_cpu_to_be_32(priv_session->ipsec.esn.value); 1182 desc_md->esn.hi = 0; 1183 } 1184 1185 desc_md->enc = 1; 1186 desc_md->sa_idx = rte_cpu_to_be_32(priv_session->sa_index); 1187 } 1188 1189 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 for (i = 0; i < len; i++) 1215 *errors += *perror++; 1216 1217 *errors -= sa_discard_stats->ipv4_id_counter; 1218 } 1219 1220 static int 1221 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 msg.cmd = NFP_IPSEC_CFG_MSG_GET_SA_STATS; 1238 msg.sa_idx = priv_session->sa_index; 1239 net_hw = eth_dev->data->dev_private; 1240 1241 ret = nfp_ipsec_cfg_cmd_issue(net_hw, &msg); 1242 if (ret < 0) { 1243 PMD_DRV_LOG(ERR, "Failed to get SA stats"); 1244 return ret; 1245 } 1246 1247 cfg_s = &msg.cfg_get_stats; 1248 direction = priv_session->ipsec.direction; 1249 memset(stats, 0, sizeof(struct rte_security_stats)); /* Start with zeros */ 1250 stats->protocol = RTE_SECURITY_PROTOCOL_IPSEC; 1251 ips_s = &stats->ipsec; 1252 1253 /* Only display SA if any counters are non-zero */ 1254 if (cfg_s->lifetime_byte_count != 0 || cfg_s->pkt_count != 0) { 1255 if (direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) { 1256 ips_s->ipackets = cfg_s->pkt_count; 1257 ips_s->ibytes = cfg_s->lifetime_byte_count; 1258 nfp_get_errorstats(&ips_s->ierrors, &cfg_s->sa_discard_stats); 1259 } else { 1260 ips_s->opackets = cfg_s->pkt_count; 1261 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 nfp_crypto_capabilities_get(void *device __rte_unused) 1271 { 1272 return nfp_security_caps; 1273 } 1274 1275 static uint32_t 1276 nfp_security_session_get_size(void *device __rte_unused) 1277 { 1278 return sizeof(struct nfp_ipsec_session); 1279 } 1280 1281 static int 1282 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 sa_index = priv_session->sa_index; 1291 net_hw = eth_dev->data->dev_private; 1292 1293 cfg.cmd = NFP_IPSEC_CFG_MSG_INV_SA; 1294 cfg.sa_idx = sa_index; 1295 ret = nfp_ipsec_cfg_cmd_issue(net_hw, &cfg); 1296 if (ret < 0) { 1297 PMD_DRV_LOG(ERR, "Failed to remove SA!"); 1298 return -EINVAL; 1299 } 1300 1301 net_hw->ipsec_data->sa_free_cnt++; 1302 net_hw->ipsec_data->sa_entries[sa_index] = NULL; 1303 1304 return 0; 1305 } 1306 1307 static int 1308 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 priv_session = SECURITY_GET_SESS_PRIV(session); 1317 if (eth_dev != priv_session->dev) { 1318 PMD_DRV_LOG(ERR, "Session not bound to this device"); 1319 return -ENODEV; 1320 } 1321 1322 ret = nfp_crypto_remove_sa(eth_dev, priv_session); 1323 if (ret < 0) { 1324 PMD_DRV_LOG(ERR, "Failed to remove session"); 1325 return -EFAULT; 1326 } 1327 1328 memset(priv_session, 0, sizeof(struct nfp_ipsec_session)); 1329 1330 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 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 ctx = rte_zmalloc("security_ctx", 1355 sizeof(struct rte_security_ctx), 0); 1356 if (ctx == NULL) { 1357 PMD_INIT_LOG(ERR, "Failed to malloc security_ctx"); 1358 return -ENOMEM; 1359 } 1360 1361 ctx->device = dev; 1362 ctx->ops = &nfp_security_ops; 1363 ctx->sess_cnt = 0; 1364 dev->security_ctx = ctx; 1365 1366 data->pkt_dynfield_offset = rte_mbuf_dynfield_register(&pkt_md_dynfield); 1367 if (data->pkt_dynfield_offset < 0) { 1368 PMD_INIT_LOG(ERR, "Failed to register mbuf esn_dynfield"); 1369 return -ENOMEM; 1370 } 1371 1372 return 0; 1373 } 1374 1375 int 1376 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 net_hw = dev->data->dev_private; 1384 1385 cap_extend = net_hw->super.cap_ext; 1386 if ((cap_extend & NFP_NET_CFG_CTRL_IPSEC) == 0) { 1387 PMD_INIT_LOG(INFO, "Unsupported IPsec extend capability"); 1388 return 0; 1389 } 1390 1391 data = rte_zmalloc("ipsec_data", sizeof(struct nfp_net_ipsec_data), 0); 1392 if (data == NULL) { 1393 PMD_INIT_LOG(ERR, "Failed to malloc ipsec_data"); 1394 return -ENOMEM; 1395 } 1396 1397 data->pkt_dynfield_offset = -1; 1398 data->sa_free_cnt = NFP_NET_IPSEC_MAX_SA_CNT; 1399 net_hw->ipsec_data = data; 1400 1401 ret = nfp_ipsec_ctx_create(dev, data); 1402 if (ret != 0) { 1403 PMD_INIT_LOG(ERR, "Failed to create IPsec ctx"); 1404 goto ipsec_cleanup; 1405 } 1406 1407 return 0; 1408 1409 ipsec_cleanup: 1410 nfp_ipsec_uninit(dev); 1411 1412 return ret; 1413 } 1414 1415 static void 1416 nfp_ipsec_ctx_destroy(struct rte_eth_dev *dev) 1417 { 1418 if (dev->security_ctx != NULL) 1419 rte_free(dev->security_ctx); 1420 } 1421 1422 void 1423 nfp_ipsec_uninit(struct rte_eth_dev *dev) 1424 { 1425 uint16_t i; 1426 uint32_t cap_extend; 1427 struct nfp_net_hw *net_hw; 1428 struct nfp_ipsec_session *priv_session; 1429 1430 net_hw = dev->data->dev_private; 1431 1432 cap_extend = net_hw->super.cap_ext; 1433 if ((cap_extend & NFP_NET_CFG_CTRL_IPSEC) == 0) { 1434 PMD_INIT_LOG(INFO, "Unsupported IPsec extend capability"); 1435 return; 1436 } 1437 1438 nfp_ipsec_ctx_destroy(dev); 1439 1440 if (net_hw->ipsec_data == NULL) { 1441 PMD_INIT_LOG(INFO, "IPsec data is NULL!"); 1442 return; 1443 } 1444 1445 for (i = 0; i < NFP_NET_IPSEC_MAX_SA_CNT; i++) { 1446 priv_session = net_hw->ipsec_data->sa_entries[i]; 1447 if (priv_session != NULL) 1448 memset(priv_session, 0, sizeof(struct nfp_ipsec_session)); 1449 } 1450 1451 rte_free(net_hw->ipsec_data); 1452 } 1453 1454