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