154713740SChang Miao /* SPDX-License-Identifier: BSD-3-Clause 254713740SChang Miao * Copyright (c) 2023 Corigine Systems, Inc. 354713740SChang Miao * All rights reserved. 454713740SChang Miao */ 554713740SChang Miao 654713740SChang Miao #include "nfp_ipsec.h" 754713740SChang Miao 8e6d69ea0SShihong Wang #include <rte_cryptodev.h> 954713740SChang Miao #include <rte_malloc.h> 1054713740SChang Miao #include <rte_security_driver.h> 1154713740SChang Miao 1254713740SChang Miao #include <ethdev_driver.h> 1354713740SChang Miao #include <ethdev_pci.h> 1454713740SChang Miao 1554713740SChang Miao #include "nfp_logs.h" 1611e9eae4SChaoyong He #include "nfp_net_common.h" 17*e2018e37SChaoyong He #include "nfp_net_ctrl.h" 1854713740SChang Miao #include "nfp_rxtx.h" 1954713740SChang Miao 203d21da66SChang Miao #define NFP_UDP_ESP_PORT 4500 213d21da66SChang Miao 22e6d69ea0SShihong Wang static const struct rte_cryptodev_capabilities nfp_crypto_caps[] = { 23e6d69ea0SShihong Wang { 24e6d69ea0SShihong Wang .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC, 25e6d69ea0SShihong Wang .sym = { 26e6d69ea0SShihong Wang .xform_type = RTE_CRYPTO_SYM_XFORM_AUTH, 27e6d69ea0SShihong Wang .auth = { 28e6d69ea0SShihong Wang .algo = RTE_CRYPTO_AUTH_MD5_HMAC, 29e6d69ea0SShihong Wang .block_size = 64, 30e6d69ea0SShihong Wang .key_size = { 31e6d69ea0SShihong Wang .min = 16, 32e6d69ea0SShihong Wang .max = 16, 33e6d69ea0SShihong Wang .increment = 0 34e6d69ea0SShihong Wang }, 35e6d69ea0SShihong Wang .digest_size = { 36e6d69ea0SShihong Wang .min = 12, 37e6d69ea0SShihong Wang .max = 16, 38e6d69ea0SShihong Wang .increment = 4 39e6d69ea0SShihong Wang }, 40e6d69ea0SShihong Wang }, 41e6d69ea0SShihong Wang }, 42e6d69ea0SShihong Wang }, 43e6d69ea0SShihong Wang { 44e6d69ea0SShihong Wang .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC, 45e6d69ea0SShihong Wang .sym = { 46e6d69ea0SShihong Wang .xform_type = RTE_CRYPTO_SYM_XFORM_AUTH, 47e6d69ea0SShihong Wang .auth = { 48e6d69ea0SShihong Wang .algo = RTE_CRYPTO_AUTH_SHA1_HMAC, 49e6d69ea0SShihong Wang .block_size = 64, 50e6d69ea0SShihong Wang .key_size = { 51e6d69ea0SShihong Wang .min = 20, 52e6d69ea0SShihong Wang .max = 64, 53e6d69ea0SShihong Wang .increment = 1 54e6d69ea0SShihong Wang }, 55e6d69ea0SShihong Wang .digest_size = { 56e6d69ea0SShihong Wang .min = 10, 57e6d69ea0SShihong Wang .max = 12, 58e6d69ea0SShihong Wang .increment = 2 59e6d69ea0SShihong Wang }, 60e6d69ea0SShihong Wang }, 61e6d69ea0SShihong Wang }, 62e6d69ea0SShihong Wang }, 63e6d69ea0SShihong Wang { 64e6d69ea0SShihong Wang .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC, 65e6d69ea0SShihong Wang .sym = { 66e6d69ea0SShihong Wang .xform_type = RTE_CRYPTO_SYM_XFORM_AUTH, 67e6d69ea0SShihong Wang .auth = { 68e6d69ea0SShihong Wang .algo = RTE_CRYPTO_AUTH_SHA256_HMAC, 69e6d69ea0SShihong Wang .block_size = 64, 70e6d69ea0SShihong Wang .key_size = { 71e6d69ea0SShihong Wang .min = 32, 72e6d69ea0SShihong Wang .max = 32, 73e6d69ea0SShihong Wang .increment = 0 74e6d69ea0SShihong Wang }, 75e6d69ea0SShihong Wang .digest_size = { 76e6d69ea0SShihong Wang .min = 12, 77e6d69ea0SShihong Wang .max = 16, 78e6d69ea0SShihong Wang .increment = 4 79e6d69ea0SShihong Wang }, 80e6d69ea0SShihong Wang }, 81e6d69ea0SShihong Wang }, 82e6d69ea0SShihong Wang }, 83e6d69ea0SShihong Wang { 84e6d69ea0SShihong Wang .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC, 85e6d69ea0SShihong Wang .sym = { 86e6d69ea0SShihong Wang .xform_type = RTE_CRYPTO_SYM_XFORM_AUTH, 87e6d69ea0SShihong Wang .auth = { 88e6d69ea0SShihong Wang .algo = RTE_CRYPTO_AUTH_SHA384_HMAC, 89e6d69ea0SShihong Wang .block_size = 128, 90e6d69ea0SShihong Wang .key_size = { 91e6d69ea0SShihong Wang .min = 48, 92e6d69ea0SShihong Wang .max = 48, 93e6d69ea0SShihong Wang .increment = 0 94e6d69ea0SShihong Wang }, 95e6d69ea0SShihong Wang .digest_size = { 96e6d69ea0SShihong Wang .min = 12, 97e6d69ea0SShihong Wang .max = 24, 98e6d69ea0SShihong Wang .increment = 12 99e6d69ea0SShihong Wang }, 100e6d69ea0SShihong Wang }, 101e6d69ea0SShihong Wang }, 102e6d69ea0SShihong Wang }, 103e6d69ea0SShihong Wang { 104e6d69ea0SShihong Wang .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC, 105e6d69ea0SShihong Wang .sym = { 106e6d69ea0SShihong Wang .xform_type = RTE_CRYPTO_SYM_XFORM_AUTH, 107e6d69ea0SShihong Wang .auth = { 108e6d69ea0SShihong Wang .algo = RTE_CRYPTO_AUTH_SHA512_HMAC, 109e6d69ea0SShihong Wang .block_size = 128, 110e6d69ea0SShihong Wang .key_size = { 111e6d69ea0SShihong Wang .min = 64, 112e6d69ea0SShihong Wang .max = 64, 113e6d69ea0SShihong Wang .increment = 1 114e6d69ea0SShihong Wang }, 115e6d69ea0SShihong Wang .digest_size = { 116e6d69ea0SShihong Wang .min = 12, 117e6d69ea0SShihong Wang .max = 32, 118e6d69ea0SShihong Wang .increment = 4 119e6d69ea0SShihong Wang }, 120e6d69ea0SShihong Wang }, 121e6d69ea0SShihong Wang }, 122e6d69ea0SShihong Wang }, 123e6d69ea0SShihong Wang { 124e6d69ea0SShihong Wang .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC, 125e6d69ea0SShihong Wang .sym = { 126e6d69ea0SShihong Wang .xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER, 127e6d69ea0SShihong Wang .cipher = { 128e6d69ea0SShihong Wang .algo = RTE_CRYPTO_CIPHER_3DES_CBC, 129e6d69ea0SShihong Wang .block_size = 8, 130e6d69ea0SShihong Wang .key_size = { 131e6d69ea0SShihong Wang .min = 24, 132e6d69ea0SShihong Wang .max = 24, 133e6d69ea0SShihong Wang .increment = 0 134e6d69ea0SShihong Wang }, 135e6d69ea0SShihong Wang .iv_size = { 136e6d69ea0SShihong Wang .min = 8, 137e6d69ea0SShihong Wang .max = 16, 138e6d69ea0SShihong Wang .increment = 8 139e6d69ea0SShihong Wang }, 140e6d69ea0SShihong Wang }, 141e6d69ea0SShihong Wang }, 142e6d69ea0SShihong Wang }, 143e6d69ea0SShihong Wang { 144e6d69ea0SShihong Wang .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC, 145e6d69ea0SShihong Wang .sym = { 146e6d69ea0SShihong Wang .xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER, 147e6d69ea0SShihong Wang .cipher = { 148e6d69ea0SShihong Wang .algo = RTE_CRYPTO_CIPHER_AES_CBC, 149e6d69ea0SShihong Wang .block_size = 16, 150e6d69ea0SShihong Wang .key_size = { 151e6d69ea0SShihong Wang .min = 16, 152e6d69ea0SShihong Wang .max = 32, 153e6d69ea0SShihong Wang .increment = 8 154e6d69ea0SShihong Wang }, 155e6d69ea0SShihong Wang .iv_size = { 156e6d69ea0SShihong Wang .min = 8, 157e6d69ea0SShihong Wang .max = 16, 158e6d69ea0SShihong Wang .increment = 8 159e6d69ea0SShihong Wang }, 160e6d69ea0SShihong Wang }, 161e6d69ea0SShihong Wang }, 162e6d69ea0SShihong Wang }, 163e6d69ea0SShihong Wang { 164e6d69ea0SShihong Wang .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC, 165e6d69ea0SShihong Wang .sym = { 166e6d69ea0SShihong Wang .xform_type = RTE_CRYPTO_SYM_XFORM_AEAD, 167e6d69ea0SShihong Wang .aead = { 168e6d69ea0SShihong Wang .algo = RTE_CRYPTO_AEAD_AES_GCM, 169e6d69ea0SShihong Wang .block_size = 16, 170e6d69ea0SShihong Wang .key_size = { 171e6d69ea0SShihong Wang .min = 16, 172e6d69ea0SShihong Wang .max = 32, 173e6d69ea0SShihong Wang .increment = 8 174e6d69ea0SShihong Wang }, 175e6d69ea0SShihong Wang .digest_size = { 176e6d69ea0SShihong Wang .min = 16, 177e6d69ea0SShihong Wang .max = 16, 178e6d69ea0SShihong Wang .increment = 0 179e6d69ea0SShihong Wang }, 180e6d69ea0SShihong Wang .aad_size = { 181e6d69ea0SShihong Wang .min = 0, 182e6d69ea0SShihong Wang .max = 1024, 183e6d69ea0SShihong Wang .increment = 1 184e6d69ea0SShihong Wang }, 185e6d69ea0SShihong Wang .iv_size = { 186e6d69ea0SShihong Wang .min = 8, 187e6d69ea0SShihong Wang .max = 16, 188e6d69ea0SShihong Wang .increment = 4 189e6d69ea0SShihong Wang } 190e6d69ea0SShihong Wang }, 191e6d69ea0SShihong Wang }, 192e6d69ea0SShihong Wang }, 193e6d69ea0SShihong Wang { 194e6d69ea0SShihong Wang .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC, 195e6d69ea0SShihong Wang .sym = { 196e6d69ea0SShihong Wang .xform_type = RTE_CRYPTO_SYM_XFORM_AEAD, 197e6d69ea0SShihong Wang .aead = { 198e6d69ea0SShihong Wang .algo = RTE_CRYPTO_AEAD_CHACHA20_POLY1305, 199e6d69ea0SShihong Wang .block_size = 16, 200e6d69ea0SShihong Wang .key_size = { 201e6d69ea0SShihong Wang .min = 32, 202e6d69ea0SShihong Wang .max = 32, 203e6d69ea0SShihong Wang .increment = 0 204e6d69ea0SShihong Wang }, 205e6d69ea0SShihong Wang .digest_size = { 206e6d69ea0SShihong Wang .min = 16, 207e6d69ea0SShihong Wang .max = 16, 208e6d69ea0SShihong Wang .increment = 0 209e6d69ea0SShihong Wang }, 210e6d69ea0SShihong Wang .aad_size = { 211e6d69ea0SShihong Wang .min = 0, 212e6d69ea0SShihong Wang .max = 1024, 213e6d69ea0SShihong Wang .increment = 1 214e6d69ea0SShihong Wang }, 215e6d69ea0SShihong Wang .iv_size = { 216e6d69ea0SShihong Wang .min = 8, 217e6d69ea0SShihong Wang .max = 16, 218e6d69ea0SShihong Wang .increment = 4 219e6d69ea0SShihong Wang } 220e6d69ea0SShihong Wang }, 221e6d69ea0SShihong Wang }, 222e6d69ea0SShihong Wang }, 223e6d69ea0SShihong Wang { 224e6d69ea0SShihong Wang .op = RTE_CRYPTO_OP_TYPE_UNDEFINED, 225e6d69ea0SShihong Wang .sym = { 226e6d69ea0SShihong Wang .xform_type = RTE_CRYPTO_SYM_XFORM_NOT_SPECIFIED 227e6d69ea0SShihong Wang }, 228e6d69ea0SShihong Wang } 229e6d69ea0SShihong Wang }; 230e6d69ea0SShihong Wang 231e6d69ea0SShihong Wang static const struct rte_security_capability nfp_security_caps[] = { 232e6d69ea0SShihong Wang { /* IPsec Inline Crypto Tunnel Egress */ 233e6d69ea0SShihong Wang .action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO, 234e6d69ea0SShihong Wang .protocol = RTE_SECURITY_PROTOCOL_IPSEC, 235e6d69ea0SShihong Wang .ipsec = { 236e6d69ea0SShihong Wang .mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL, 237e6d69ea0SShihong Wang .direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS, 238e6d69ea0SShihong Wang .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP, 239e6d69ea0SShihong Wang .options = { 240e6d69ea0SShihong Wang .udp_encap = 1, 241e6d69ea0SShihong Wang .stats = 1, 242e6d69ea0SShihong Wang .esn = 1 243e6d69ea0SShihong Wang } 244e6d69ea0SShihong Wang }, 245e6d69ea0SShihong Wang .crypto_capabilities = nfp_crypto_caps 246e6d69ea0SShihong Wang }, 247e6d69ea0SShihong Wang { /* IPsec Inline Crypto Tunnel Ingress */ 248e6d69ea0SShihong Wang .action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO, 249e6d69ea0SShihong Wang .protocol = RTE_SECURITY_PROTOCOL_IPSEC, 250e6d69ea0SShihong Wang .ipsec = { 251e6d69ea0SShihong Wang .mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL, 252e6d69ea0SShihong Wang .direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS, 253e6d69ea0SShihong Wang .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP, 254e6d69ea0SShihong Wang .options = { 255e6d69ea0SShihong Wang .udp_encap = 1, 256e6d69ea0SShihong Wang .stats = 1, 257e6d69ea0SShihong Wang .esn = 1 258e6d69ea0SShihong Wang } 259e6d69ea0SShihong Wang }, 260e6d69ea0SShihong Wang .crypto_capabilities = nfp_crypto_caps, 261e6d69ea0SShihong Wang .ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA 262e6d69ea0SShihong Wang }, 263e6d69ea0SShihong Wang { /* IPsec Inline Crypto Transport Egress */ 264e6d69ea0SShihong Wang .action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO, 265e6d69ea0SShihong Wang .protocol = RTE_SECURITY_PROTOCOL_IPSEC, 266e6d69ea0SShihong Wang .ipsec = { 267e6d69ea0SShihong Wang .mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT, 268e6d69ea0SShihong Wang .direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS, 269e6d69ea0SShihong Wang .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP, 270e6d69ea0SShihong Wang .options = { 271e6d69ea0SShihong Wang .udp_encap = 1, 272e6d69ea0SShihong Wang .stats = 1, 273e6d69ea0SShihong Wang .esn = 1 274e6d69ea0SShihong Wang } 275e6d69ea0SShihong Wang }, 276e6d69ea0SShihong Wang .crypto_capabilities = nfp_crypto_caps 277e6d69ea0SShihong Wang }, 278e6d69ea0SShihong Wang { /* IPsec Inline Crypto Transport Ingress */ 279e6d69ea0SShihong Wang .action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO, 280e6d69ea0SShihong Wang .protocol = RTE_SECURITY_PROTOCOL_IPSEC, 281e6d69ea0SShihong Wang .ipsec = { 282e6d69ea0SShihong Wang .mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT, 283e6d69ea0SShihong Wang .direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS, 284e6d69ea0SShihong Wang .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP, 285e6d69ea0SShihong Wang .options = { 286e6d69ea0SShihong Wang .udp_encap = 1, 287e6d69ea0SShihong Wang .stats = 1, 288e6d69ea0SShihong Wang .esn = 1 289e6d69ea0SShihong Wang } 290e6d69ea0SShihong Wang }, 291e6d69ea0SShihong Wang .crypto_capabilities = nfp_crypto_caps, 292e6d69ea0SShihong Wang .ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA 293e6d69ea0SShihong Wang }, 294e6d69ea0SShihong Wang { /* IPsec Inline Protocol Tunnel Egress */ 295e6d69ea0SShihong Wang .action = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL, 296e6d69ea0SShihong Wang .protocol = RTE_SECURITY_PROTOCOL_IPSEC, 297e6d69ea0SShihong Wang .ipsec = { 298e6d69ea0SShihong Wang .mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL, 299e6d69ea0SShihong Wang .direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS, 300e6d69ea0SShihong Wang .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP, 301e6d69ea0SShihong Wang .options = { 302e6d69ea0SShihong Wang .udp_encap = 1, 303e6d69ea0SShihong Wang .stats = 1, 304e6d69ea0SShihong Wang .esn = 1 305e6d69ea0SShihong Wang } 306e6d69ea0SShihong Wang }, 307e6d69ea0SShihong Wang .crypto_capabilities = nfp_crypto_caps 308e6d69ea0SShihong Wang }, 309e6d69ea0SShihong Wang { /* IPsec Inline Protocol Tunnel Ingress */ 310e6d69ea0SShihong Wang .action = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL, 311e6d69ea0SShihong Wang .protocol = RTE_SECURITY_PROTOCOL_IPSEC, 312e6d69ea0SShihong Wang .ipsec = { 313e6d69ea0SShihong Wang .mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL, 314e6d69ea0SShihong Wang .direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS, 315e6d69ea0SShihong Wang .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP, 316e6d69ea0SShihong Wang .options = { 317e6d69ea0SShihong Wang .udp_encap = 1, 318e6d69ea0SShihong Wang .stats = 1, 319e6d69ea0SShihong Wang .esn = 1 320e6d69ea0SShihong Wang } 321e6d69ea0SShihong Wang }, 322e6d69ea0SShihong Wang .crypto_capabilities = nfp_crypto_caps, 323e6d69ea0SShihong Wang .ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA 324e6d69ea0SShihong Wang }, 325e6d69ea0SShihong Wang { /* IPsec Inline Protocol Transport Egress */ 326e6d69ea0SShihong Wang .action = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL, 327e6d69ea0SShihong Wang .protocol = RTE_SECURITY_PROTOCOL_IPSEC, 328e6d69ea0SShihong Wang .ipsec = { 329e6d69ea0SShihong Wang .mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT, 330e6d69ea0SShihong Wang .direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS, 331e6d69ea0SShihong Wang .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP, 332e6d69ea0SShihong Wang .options = { 333e6d69ea0SShihong Wang .udp_encap = 1, 334e6d69ea0SShihong Wang .stats = 1, 335e6d69ea0SShihong Wang .esn = 1 336e6d69ea0SShihong Wang } 337e6d69ea0SShihong Wang }, 338e6d69ea0SShihong Wang .crypto_capabilities = nfp_crypto_caps 339e6d69ea0SShihong Wang }, 340e6d69ea0SShihong Wang { /* IPsec Inline Protocol Transport Ingress */ 341e6d69ea0SShihong Wang .action = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL, 342e6d69ea0SShihong Wang .protocol = RTE_SECURITY_PROTOCOL_IPSEC, 343e6d69ea0SShihong Wang .ipsec = { 344e6d69ea0SShihong Wang .mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT, 345e6d69ea0SShihong Wang .direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS, 346e6d69ea0SShihong Wang .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP, 347e6d69ea0SShihong Wang .options = { 348e6d69ea0SShihong Wang .udp_encap = 1, 349e6d69ea0SShihong Wang .stats = 1, 350e6d69ea0SShihong Wang .esn = 1 351e6d69ea0SShihong Wang } 352e6d69ea0SShihong Wang }, 353e6d69ea0SShihong Wang .crypto_capabilities = nfp_crypto_caps, 354e6d69ea0SShihong Wang .ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA 355e6d69ea0SShihong Wang }, 356e6d69ea0SShihong Wang { 357e6d69ea0SShihong Wang .action = RTE_SECURITY_ACTION_TYPE_NONE 358e6d69ea0SShihong Wang } 359e6d69ea0SShihong Wang }; 360e6d69ea0SShihong Wang 3617fb333e9SShihong Wang /* IPsec config message cmd codes */ 3627fb333e9SShihong Wang enum nfp_ipsec_cfg_msg_cmd_codes { 3637fb333e9SShihong Wang NFP_IPSEC_CFG_MSG_ADD_SA, /**< Add a new SA */ 3647fb333e9SShihong Wang NFP_IPSEC_CFG_MSG_INV_SA, /**< Invalidate an existing SA */ 3657fb333e9SShihong Wang NFP_IPSEC_CFG_MSG_MODIFY_SA, /**< Modify an existing SA */ 3667fb333e9SShihong Wang NFP_IPSEC_CFG_MSG_GET_SA_STATS, /**< Report SA counters, flags, etc. */ 3677fb333e9SShihong Wang NFP_IPSEC_CFG_MSG_GET_SEQ_NUMS, /**< Allocate sequence numbers */ 3687fb333e9SShihong Wang NFP_IPSEC_CFG_MSG_LAST 3697fb333e9SShihong Wang }; 3707fb333e9SShihong Wang 3717fb333e9SShihong Wang enum nfp_ipsec_cfg_msg_rsp_codes { 3727fb333e9SShihong Wang NFP_IPSEC_CFG_MSG_OK, 3737fb333e9SShihong Wang NFP_IPSEC_CFG_MSG_FAILED, 3747fb333e9SShihong Wang NFP_IPSEC_CFG_MSG_SA_VALID, 3757fb333e9SShihong Wang NFP_IPSEC_CFG_MSG_SA_HASH_ADD_FAILED, 3767fb333e9SShihong Wang NFP_IPSEC_CFG_MSG_SA_HASH_DEL_FAILED, 3777fb333e9SShihong Wang NFP_IPSEC_CFG_MSG_SA_INVALID_CMD 3787fb333e9SShihong Wang }; 3797fb333e9SShihong Wang 3803d21da66SChang Miao enum nfp_ipsec_mode { 3813d21da66SChang Miao NFP_IPSEC_MODE_TRANSPORT, 3823d21da66SChang Miao NFP_IPSEC_MODE_TUNNEL, 3833d21da66SChang Miao }; 3843d21da66SChang Miao 3853d21da66SChang Miao enum nfp_ipsec_protocol { 3863d21da66SChang Miao NFP_IPSEC_PROTOCOL_AH, 3873d21da66SChang Miao NFP_IPSEC_PROTOCOL_ESP, 3883d21da66SChang Miao }; 3893d21da66SChang Miao 3903d21da66SChang Miao /* Cipher modes */ 3913d21da66SChang Miao enum nfp_ipsec_cimode { 3923d21da66SChang Miao NFP_IPSEC_CIMODE_ECB, 3933d21da66SChang Miao NFP_IPSEC_CIMODE_CBC, 3943d21da66SChang Miao NFP_IPSEC_CIMODE_CFB, 3953d21da66SChang Miao NFP_IPSEC_CIMODE_OFB, 3963d21da66SChang Miao NFP_IPSEC_CIMODE_CTR, 3973d21da66SChang Miao }; 3983d21da66SChang Miao 3993d21da66SChang Miao /* Hash types */ 4003d21da66SChang Miao enum nfp_ipsec_hash_type { 4013d21da66SChang Miao NFP_IPSEC_HASH_NONE, 4023d21da66SChang Miao NFP_IPSEC_HASH_MD5_96, 4033d21da66SChang Miao NFP_IPSEC_HASH_SHA1_96, 4043d21da66SChang Miao NFP_IPSEC_HASH_SHA256_96, 4053d21da66SChang Miao NFP_IPSEC_HASH_SHA384_96, 4063d21da66SChang Miao NFP_IPSEC_HASH_SHA512_96, 4073d21da66SChang Miao NFP_IPSEC_HASH_MD5_128, 4083d21da66SChang Miao NFP_IPSEC_HASH_SHA1_80, 4093d21da66SChang Miao NFP_IPSEC_HASH_SHA256_128, 4103d21da66SChang Miao NFP_IPSEC_HASH_SHA384_192, 4113d21da66SChang Miao NFP_IPSEC_HASH_SHA512_256, 4123d21da66SChang Miao NFP_IPSEC_HASH_GF128_128, 4133d21da66SChang Miao NFP_IPSEC_HASH_POLY1305_128, 4143d21da66SChang Miao }; 4153d21da66SChang Miao 4163d21da66SChang Miao /* Cipher types */ 4173d21da66SChang Miao enum nfp_ipsec_cipher_type { 4183d21da66SChang Miao NFP_IPSEC_CIPHER_NULL, 4193d21da66SChang Miao NFP_IPSEC_CIPHER_3DES, 4203d21da66SChang Miao NFP_IPSEC_CIPHER_AES128, 4213d21da66SChang Miao NFP_IPSEC_CIPHER_AES192, 4223d21da66SChang Miao NFP_IPSEC_CIPHER_AES256, 4233d21da66SChang Miao NFP_IPSEC_CIPHER_AES128_NULL, 4243d21da66SChang Miao NFP_IPSEC_CIPHER_AES192_NULL, 4253d21da66SChang Miao NFP_IPSEC_CIPHER_AES256_NULL, 4263d21da66SChang Miao NFP_IPSEC_CIPHER_CHACHA20, 4273d21da66SChang Miao }; 4283d21da66SChang Miao 4293d21da66SChang Miao /* Don't Fragment types */ 4303d21da66SChang Miao enum nfp_ipsec_df_type { 4313d21da66SChang Miao NFP_IPSEC_DF_CLEAR, 4323d21da66SChang Miao NFP_IPSEC_DF_SET, 4333d21da66SChang Miao NFP_IPSEC_DF_COPY, 4343d21da66SChang Miao }; 4353d21da66SChang Miao 4367fb333e9SShihong Wang static int 4377fb333e9SShihong Wang nfp_ipsec_cfg_cmd_issue(struct nfp_net_hw *hw, 4387fb333e9SShihong Wang struct nfp_ipsec_msg *msg) 4397fb333e9SShihong Wang { 4407fb333e9SShihong Wang int ret; 4417fb333e9SShihong Wang uint32_t i; 4427fb333e9SShihong Wang uint32_t msg_size; 4437fb333e9SShihong Wang 4447fb333e9SShihong Wang msg_size = RTE_DIM(msg->raw); 4457fb333e9SShihong Wang msg->rsp = NFP_IPSEC_CFG_MSG_OK; 4467fb333e9SShihong Wang 4477fb333e9SShihong Wang for (i = 0; i < msg_size; i++) 4487fb333e9SShihong Wang nn_cfg_writel(hw, NFP_NET_CFG_MBOX_VAL + 4 * i, msg->raw[i]); 4497fb333e9SShihong Wang 4507fb333e9SShihong Wang ret = nfp_net_mbox_reconfig(hw, NFP_NET_CFG_MBOX_CMD_IPSEC); 4517fb333e9SShihong Wang if (ret < 0) { 4527fb333e9SShihong Wang PMD_DRV_LOG(ERR, "Failed to IPsec reconfig mbox"); 4537fb333e9SShihong Wang return ret; 4547fb333e9SShihong Wang } 4557fb333e9SShihong Wang 4567fb333e9SShihong Wang /* 4577fb333e9SShihong Wang * Not all commands and callers make use of response message data. But 4587fb333e9SShihong Wang * leave this up to the caller and always read and store the full 4597fb333e9SShihong Wang * response. One example where the data is needed is for statistics. 4607fb333e9SShihong Wang */ 4617fb333e9SShihong Wang for (i = 0; i < msg_size; i++) 4627fb333e9SShihong Wang msg->raw[i] = nn_cfg_readl(hw, NFP_NET_CFG_MBOX_VAL + 4 * i); 4637fb333e9SShihong Wang 4647fb333e9SShihong Wang switch (msg->rsp) { 4657fb333e9SShihong Wang case NFP_IPSEC_CFG_MSG_OK: 4667fb333e9SShihong Wang ret = 0; 4677fb333e9SShihong Wang break; 4687fb333e9SShihong Wang case NFP_IPSEC_CFG_MSG_SA_INVALID_CMD: 4697fb333e9SShihong Wang ret = -EINVAL; 4707fb333e9SShihong Wang break; 4717fb333e9SShihong Wang case NFP_IPSEC_CFG_MSG_SA_VALID: 4727fb333e9SShihong Wang ret = -EEXIST; 4737fb333e9SShihong Wang break; 4747fb333e9SShihong Wang case NFP_IPSEC_CFG_MSG_FAILED: 4757fb333e9SShihong Wang /* FALLTHROUGH */ 4767fb333e9SShihong Wang case NFP_IPSEC_CFG_MSG_SA_HASH_ADD_FAILED: 4777fb333e9SShihong Wang /* FALLTHROUGH */ 4787fb333e9SShihong Wang case NFP_IPSEC_CFG_MSG_SA_HASH_DEL_FAILED: 4797fb333e9SShihong Wang ret = -EIO; 4807fb333e9SShihong Wang break; 4817fb333e9SShihong Wang default: 4827fb333e9SShihong Wang ret = -EDOM; 4837fb333e9SShihong Wang } 4847fb333e9SShihong Wang 4857fb333e9SShihong Wang return ret; 4867fb333e9SShihong Wang } 4877fb333e9SShihong Wang 4887fb333e9SShihong Wang /** 4893d21da66SChang Miao * Get valid SA index from SA table 4903d21da66SChang Miao * 4913d21da66SChang Miao * @param data 4923d21da66SChang Miao * SA table pointer 4933d21da66SChang Miao * @param sa_idx 4943d21da66SChang Miao * SA table index pointer 4953d21da66SChang Miao * 4963d21da66SChang Miao * @return 4973d21da66SChang Miao * Negative number on full or repeat, 0 on success 4983d21da66SChang Miao * 4993d21da66SChang Miao * Note: multiple sockets may create same SA session. 5003d21da66SChang Miao */ 5013d21da66SChang Miao static void 5023d21da66SChang Miao nfp_get_sa_entry(struct nfp_net_ipsec_data *data, 5033d21da66SChang Miao int *sa_idx) 5043d21da66SChang Miao { 5053d21da66SChang Miao uint32_t i; 5063d21da66SChang Miao 5073d21da66SChang Miao for (i = 0; i < NFP_NET_IPSEC_MAX_SA_CNT; i++) { 5083d21da66SChang Miao if (data->sa_entries[i] == NULL) { 5093d21da66SChang Miao *sa_idx = i; 5103d21da66SChang Miao break; 5113d21da66SChang Miao } 5123d21da66SChang Miao } 5133d21da66SChang Miao } 5143d21da66SChang Miao 5153d21da66SChang Miao static void 5163d21da66SChang Miao nfp_aesgcm_iv_update(struct ipsec_add_sa *cfg, 5173d21da66SChang Miao uint16_t iv_len, 5183d21da66SChang Miao const char *iv_string) 5193d21da66SChang Miao { 5203d21da66SChang Miao int i; 5213d21da66SChang Miao char *save; 5223d21da66SChang Miao char *iv_b; 5233d21da66SChang Miao char *iv_str; 5243d21da66SChang Miao uint8_t *cfg_iv; 5253d21da66SChang Miao 5263d21da66SChang Miao iv_str = strdup(iv_string); 5273d21da66SChang Miao cfg_iv = (uint8_t *)cfg->aesgcm_fields.iv; 5283d21da66SChang Miao 5293d21da66SChang Miao for (i = 0; i < iv_len; i++) { 5303d21da66SChang Miao iv_b = strtok_r(i ? NULL : iv_str, ",", &save); 5313d21da66SChang Miao if (iv_b == NULL) 5323d21da66SChang Miao break; 5333d21da66SChang Miao 5343d21da66SChang Miao cfg_iv[i] = strtoul(iv_b, NULL, 0); 5353d21da66SChang Miao } 5363d21da66SChang Miao 5373d21da66SChang Miao *(uint32_t *)cfg_iv = rte_be_to_cpu_32(*(uint32_t *)cfg_iv); 5383d21da66SChang Miao *(uint32_t *)&cfg_iv[4] = rte_be_to_cpu_32(*(uint32_t *)&cfg_iv[4]); 5393d21da66SChang Miao 5403d21da66SChang Miao free(iv_str); 5413d21da66SChang Miao } 5423d21da66SChang Miao 5433d21da66SChang Miao static int 5443d21da66SChang Miao set_aes_keylen(uint32_t key_length, 5453d21da66SChang Miao struct ipsec_add_sa *cfg) 5463d21da66SChang Miao { 5473d21da66SChang Miao switch (key_length << 3) { 5483d21da66SChang Miao case 128: 5493d21da66SChang Miao cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_AES128; 5503d21da66SChang Miao break; 5513d21da66SChang Miao case 192: 5523d21da66SChang Miao cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_AES192; 5533d21da66SChang Miao break; 5543d21da66SChang Miao case 256: 5553d21da66SChang Miao cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_AES256; 5563d21da66SChang Miao break; 5573d21da66SChang Miao default: 5583d21da66SChang Miao PMD_DRV_LOG(ERR, "AES cipher key length is illegal!"); 5593d21da66SChang Miao return -EINVAL; 5603d21da66SChang Miao } 5613d21da66SChang Miao 5623d21da66SChang Miao return 0; 5633d21da66SChang Miao } 5643d21da66SChang Miao 5653d21da66SChang Miao /* Map rte_security_session_conf aead algo to NFP aead algo */ 5663d21da66SChang Miao static int 5673d21da66SChang Miao nfp_aead_map(struct rte_eth_dev *eth_dev, 5683d21da66SChang Miao struct rte_crypto_aead_xform *aead, 5693d21da66SChang Miao uint32_t key_length, 5703d21da66SChang Miao struct ipsec_add_sa *cfg) 5713d21da66SChang Miao { 5723d21da66SChang Miao int ret; 5733d21da66SChang Miao uint32_t i; 5743d21da66SChang Miao uint32_t index; 5753d21da66SChang Miao uint16_t iv_len; 5763d21da66SChang Miao uint32_t offset; 5773d21da66SChang Miao uint32_t device_id; 5783d21da66SChang Miao const char *iv_str; 5793d21da66SChang Miao const uint32_t *key; 5803d21da66SChang Miao struct nfp_net_hw *hw; 5813d21da66SChang Miao 5823d21da66SChang Miao hw = NFP_NET_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); 5833d21da66SChang Miao device_id = hw->device_id; 5843d21da66SChang Miao offset = 0; 5853d21da66SChang Miao 5863d21da66SChang Miao switch (aead->algo) { 5873d21da66SChang Miao case RTE_CRYPTO_AEAD_AES_GCM: 5883d21da66SChang Miao if (aead->digest_length != 16) { 5893d21da66SChang Miao PMD_DRV_LOG(ERR, "ICV must be 128bit with RTE_CRYPTO_AEAD_AES_GCM!"); 5903d21da66SChang Miao return -EINVAL; 5913d21da66SChang Miao } 5923d21da66SChang Miao 5933d21da66SChang Miao cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CTR; 5943d21da66SChang Miao cfg->ctrl_word.hash = NFP_IPSEC_HASH_GF128_128; 5953d21da66SChang Miao 5963d21da66SChang Miao ret = set_aes_keylen(key_length, cfg); 5973d21da66SChang Miao if (ret < 0) { 5983d21da66SChang Miao PMD_DRV_LOG(ERR, "Failed to set AES_GCM key length!"); 5993d21da66SChang Miao return -EINVAL; 6003d21da66SChang Miao } 6013d21da66SChang Miao 6023d21da66SChang Miao break; 6033d21da66SChang Miao case RTE_CRYPTO_AEAD_CHACHA20_POLY1305: 6043d21da66SChang Miao if (device_id != PCI_DEVICE_ID_NFP3800_PF_NIC) { 6053d21da66SChang Miao PMD_DRV_LOG(ERR, "Unsupported aead CHACHA20_POLY1305 algorithm!"); 6063d21da66SChang Miao return -EINVAL; 6073d21da66SChang Miao } 6083d21da66SChang Miao 6093d21da66SChang Miao if (aead->digest_length != 16) { 6103d21da66SChang Miao PMD_DRV_LOG(ERR, "ICV must be 128bit with RTE_CRYPTO_AEAD_CHACHA20_POLY1305"); 6113d21da66SChang Miao return -EINVAL; 6123d21da66SChang Miao } 6133d21da66SChang Miao 6143d21da66SChang Miao /* Aead->alg_key_len includes 32-bit salt */ 6153d21da66SChang Miao if (key_length != 32) { 6163d21da66SChang Miao PMD_DRV_LOG(ERR, "Unsupported CHACHA20 key length"); 6173d21da66SChang Miao return -EINVAL; 6183d21da66SChang Miao } 6193d21da66SChang Miao 6203d21da66SChang Miao /* The CHACHA20's mode is not configured */ 6213d21da66SChang Miao cfg->ctrl_word.hash = NFP_IPSEC_HASH_POLY1305_128; 6223d21da66SChang Miao cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_CHACHA20; 6233d21da66SChang Miao break; 6243d21da66SChang Miao default: 6253d21da66SChang Miao PMD_DRV_LOG(ERR, "Unsupported aead algorithm!"); 6263d21da66SChang Miao return -EINVAL; 6273d21da66SChang Miao } 6283d21da66SChang Miao 6293d21da66SChang Miao key = (const uint32_t *)(aead->key.data); 6303d21da66SChang Miao 6313d21da66SChang Miao /* 6323d21da66SChang Miao * The CHACHA20's key order needs to be adjusted based on hardware design. 6333d21da66SChang Miao * Unadjusted order: {K0, K1, K2, K3, K4, K5, K6, K7} 6343d21da66SChang Miao * Adjusted order: {K4, K5, K6, K7, K0, K1, K2, K3} 6353d21da66SChang Miao */ 6363d21da66SChang Miao if (aead->algo == RTE_CRYPTO_AEAD_CHACHA20_POLY1305) 6373d21da66SChang Miao offset = key_length / sizeof(cfg->cipher_key[0]) << 1; 6383d21da66SChang Miao 6393d21da66SChang Miao for (i = 0; i < key_length / sizeof(cfg->cipher_key[0]); i++) { 6403d21da66SChang Miao index = (i + offset) % (key_length / sizeof(cfg->cipher_key[0])); 6413d21da66SChang Miao cfg->cipher_key[index] = rte_cpu_to_be_32(*key++); 6423d21da66SChang Miao } 6433d21da66SChang Miao 6443d21da66SChang Miao /* 6453d21da66SChang Miao * The iv of the FW is equal to ESN by default. Reading the 6463d21da66SChang Miao * iv of the configuration information is not supported. 6473d21da66SChang Miao */ 6483d21da66SChang Miao iv_str = getenv("ETH_SEC_IV_OVR"); 6493d21da66SChang Miao if (iv_str != NULL) { 6503d21da66SChang Miao iv_len = aead->iv.length; 6513d21da66SChang Miao nfp_aesgcm_iv_update(cfg, iv_len, iv_str); 6523d21da66SChang Miao } 6533d21da66SChang Miao 6543d21da66SChang Miao return 0; 6553d21da66SChang Miao } 6563d21da66SChang Miao 6573d21da66SChang Miao /* Map rte_security_session_conf cipher algo to NFP cipher algo */ 6583d21da66SChang Miao static int 6593d21da66SChang Miao nfp_cipher_map(struct rte_eth_dev *eth_dev, 6603d21da66SChang Miao struct rte_crypto_cipher_xform *cipher, 6613d21da66SChang Miao uint32_t key_length, 6623d21da66SChang Miao struct ipsec_add_sa *cfg) 6633d21da66SChang Miao { 6643d21da66SChang Miao int ret; 6653d21da66SChang Miao uint32_t i; 6663d21da66SChang Miao uint32_t device_id; 6673d21da66SChang Miao const uint32_t *key; 6683d21da66SChang Miao struct nfp_net_hw *hw; 6693d21da66SChang Miao 6703d21da66SChang Miao hw = NFP_NET_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); 6713d21da66SChang Miao device_id = hw->device_id; 6723d21da66SChang Miao 6733d21da66SChang Miao switch (cipher->algo) { 6743d21da66SChang Miao case RTE_CRYPTO_CIPHER_NULL: 6753d21da66SChang Miao cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CBC; 6763d21da66SChang Miao cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_NULL; 6773d21da66SChang Miao break; 6783d21da66SChang Miao case RTE_CRYPTO_CIPHER_3DES_CBC: 6793d21da66SChang Miao if (device_id == PCI_DEVICE_ID_NFP3800_PF_NIC) { 6803d21da66SChang Miao PMD_DRV_LOG(ERR, "Unsupported 3DESCBC encryption algorithm!"); 6813d21da66SChang Miao return -EINVAL; 6823d21da66SChang Miao } 6833d21da66SChang Miao 6843d21da66SChang Miao cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CBC; 6853d21da66SChang Miao cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_3DES; 6863d21da66SChang Miao break; 6873d21da66SChang Miao case RTE_CRYPTO_CIPHER_AES_CBC: 6883d21da66SChang Miao cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CBC; 6893d21da66SChang Miao ret = set_aes_keylen(key_length, cfg); 6903d21da66SChang Miao if (ret < 0) { 6913d21da66SChang Miao PMD_DRV_LOG(ERR, "Failed to set cipher key length!"); 6923d21da66SChang Miao return -EINVAL; 6933d21da66SChang Miao } 6943d21da66SChang Miao 6953d21da66SChang Miao break; 6963d21da66SChang Miao default: 6973d21da66SChang Miao PMD_DRV_LOG(ERR, "Unsupported cipher alg!"); 6983d21da66SChang Miao return -EINVAL; 6993d21da66SChang Miao } 7003d21da66SChang Miao 7013d21da66SChang Miao key = (const uint32_t *)(cipher->key.data); 7023d21da66SChang Miao if (key_length > sizeof(cfg->cipher_key)) { 7033d21da66SChang Miao PMD_DRV_LOG(ERR, "Insufficient space for offloaded key"); 7043d21da66SChang Miao return -EINVAL; 7053d21da66SChang Miao } 7063d21da66SChang Miao 7073d21da66SChang Miao for (i = 0; i < key_length / sizeof(cfg->cipher_key[0]); i++) 7083d21da66SChang Miao cfg->cipher_key[i] = rte_cpu_to_be_32(*key++); 7093d21da66SChang Miao 7103d21da66SChang Miao return 0; 7113d21da66SChang Miao } 7123d21da66SChang Miao 7133d21da66SChang Miao static void 7143d21da66SChang Miao set_md5hmac(struct ipsec_add_sa *cfg, 7153d21da66SChang Miao uint32_t *digest_length) 7163d21da66SChang Miao { 7173d21da66SChang Miao switch (*digest_length) { 7183d21da66SChang Miao case 96: 7193d21da66SChang Miao cfg->ctrl_word.hash = NFP_IPSEC_HASH_MD5_96; 7203d21da66SChang Miao break; 7213d21da66SChang Miao case 128: 7223d21da66SChang Miao cfg->ctrl_word.hash = NFP_IPSEC_HASH_MD5_128; 7233d21da66SChang Miao break; 7243d21da66SChang Miao default: 7253d21da66SChang Miao *digest_length = 0; 7263d21da66SChang Miao } 7273d21da66SChang Miao } 7283d21da66SChang Miao 7293d21da66SChang Miao static void 7303d21da66SChang Miao set_sha1hmac(struct ipsec_add_sa *cfg, 7313d21da66SChang Miao uint32_t *digest_length) 7323d21da66SChang Miao { 7333d21da66SChang Miao switch (*digest_length) { 7343d21da66SChang Miao case 96: 7353d21da66SChang Miao cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA1_96; 7363d21da66SChang Miao break; 7373d21da66SChang Miao case 80: 7383d21da66SChang Miao cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA1_80; 7393d21da66SChang Miao break; 7403d21da66SChang Miao default: 7413d21da66SChang Miao *digest_length = 0; 7423d21da66SChang Miao } 7433d21da66SChang Miao } 7443d21da66SChang Miao 7453d21da66SChang Miao static void 7463d21da66SChang Miao set_sha2_256hmac(struct ipsec_add_sa *cfg, 7473d21da66SChang Miao uint32_t *digest_length) 7483d21da66SChang Miao { 7493d21da66SChang Miao switch (*digest_length) { 7503d21da66SChang Miao case 96: 7513d21da66SChang Miao cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA256_96; 7523d21da66SChang Miao break; 7533d21da66SChang Miao case 128: 7543d21da66SChang Miao cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA256_128; 7553d21da66SChang Miao break; 7563d21da66SChang Miao default: 7573d21da66SChang Miao *digest_length = 0; 7583d21da66SChang Miao } 7593d21da66SChang Miao } 7603d21da66SChang Miao 7613d21da66SChang Miao static void 7623d21da66SChang Miao set_sha2_384hmac(struct ipsec_add_sa *cfg, 7633d21da66SChang Miao uint32_t *digest_length) 7643d21da66SChang Miao { 7653d21da66SChang Miao switch (*digest_length) { 7663d21da66SChang Miao case 96: 7673d21da66SChang Miao cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA384_96; 7683d21da66SChang Miao break; 7693d21da66SChang Miao case 192: 7703d21da66SChang Miao cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA384_192; 7713d21da66SChang Miao break; 7723d21da66SChang Miao default: 7733d21da66SChang Miao *digest_length = 0; 7743d21da66SChang Miao } 7753d21da66SChang Miao } 7763d21da66SChang Miao 7773d21da66SChang Miao static void 7783d21da66SChang Miao set_sha2_512hmac(struct ipsec_add_sa *cfg, 7793d21da66SChang Miao uint32_t *digest_length) 7803d21da66SChang Miao { 7813d21da66SChang Miao switch (*digest_length) { 7823d21da66SChang Miao case 96: 7833d21da66SChang Miao cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA512_96; 7843d21da66SChang Miao break; 7853d21da66SChang Miao case 256: 7863d21da66SChang Miao cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA512_256; 7873d21da66SChang Miao break; 7883d21da66SChang Miao default: 7893d21da66SChang Miao *digest_length = 0; 7903d21da66SChang Miao } 7913d21da66SChang Miao } 7923d21da66SChang Miao 7933d21da66SChang Miao /* Map rte_security_session_conf auth algo to NFP auth algo */ 7943d21da66SChang Miao static int 7953d21da66SChang Miao nfp_auth_map(struct rte_eth_dev *eth_dev, 7963d21da66SChang Miao struct rte_crypto_auth_xform *auth, 7973d21da66SChang Miao uint32_t digest_length, 7983d21da66SChang Miao struct ipsec_add_sa *cfg) 7993d21da66SChang Miao { 8003d21da66SChang Miao uint32_t i; 8013d21da66SChang Miao uint8_t key_length; 8023d21da66SChang Miao uint32_t device_id; 8033d21da66SChang Miao const uint32_t *key; 8043d21da66SChang Miao struct nfp_net_hw *hw; 8053d21da66SChang Miao 8063d21da66SChang Miao if (digest_length == 0) { 8073d21da66SChang Miao PMD_DRV_LOG(ERR, "Auth digest length is illegal!"); 8083d21da66SChang Miao return -EINVAL; 8093d21da66SChang Miao } 8103d21da66SChang Miao 8113d21da66SChang Miao hw = NFP_NET_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); 8123d21da66SChang Miao device_id = hw->device_id; 8133d21da66SChang Miao digest_length = digest_length << 3; 8143d21da66SChang Miao 8153d21da66SChang Miao switch (auth->algo) { 8163d21da66SChang Miao case RTE_CRYPTO_AUTH_NULL: 8173d21da66SChang Miao cfg->ctrl_word.hash = NFP_IPSEC_HASH_NONE; 8183d21da66SChang Miao digest_length = 1; 8193d21da66SChang Miao break; 8203d21da66SChang Miao case RTE_CRYPTO_AUTH_MD5_HMAC: 8213d21da66SChang Miao if (device_id == PCI_DEVICE_ID_NFP3800_PF_NIC) { 8223d21da66SChang Miao PMD_DRV_LOG(ERR, "Unsupported MD5HMAC authentication algorithm!"); 8233d21da66SChang Miao return -EINVAL; 8243d21da66SChang Miao } 8253d21da66SChang Miao 8263d21da66SChang Miao set_md5hmac(cfg, &digest_length); 8273d21da66SChang Miao break; 8283d21da66SChang Miao case RTE_CRYPTO_AUTH_SHA1_HMAC: 8293d21da66SChang Miao set_sha1hmac(cfg, &digest_length); 8303d21da66SChang Miao break; 8313d21da66SChang Miao case RTE_CRYPTO_AUTH_SHA256_HMAC: 8323d21da66SChang Miao set_sha2_256hmac(cfg, &digest_length); 8333d21da66SChang Miao break; 8343d21da66SChang Miao case RTE_CRYPTO_AUTH_SHA384_HMAC: 8353d21da66SChang Miao set_sha2_384hmac(cfg, &digest_length); 8363d21da66SChang Miao break; 8373d21da66SChang Miao case RTE_CRYPTO_AUTH_SHA512_HMAC: 8383d21da66SChang Miao set_sha2_512hmac(cfg, &digest_length); 8393d21da66SChang Miao break; 8403d21da66SChang Miao default: 8413d21da66SChang Miao PMD_DRV_LOG(ERR, "Unsupported auth alg!"); 8423d21da66SChang Miao return -EINVAL; 8433d21da66SChang Miao } 8443d21da66SChang Miao 8453d21da66SChang Miao if (digest_length == 0) { 8463d21da66SChang Miao PMD_DRV_LOG(ERR, "Unsupported authentication algorithm digest length"); 8473d21da66SChang Miao return -EINVAL; 8483d21da66SChang Miao } 8493d21da66SChang Miao 8503d21da66SChang Miao key = (const uint32_t *)(auth->key.data); 8513d21da66SChang Miao key_length = auth->key.length; 8523d21da66SChang Miao if (key_length > sizeof(cfg->auth_key)) { 8533d21da66SChang Miao PMD_DRV_LOG(ERR, "Insufficient space for offloaded auth key!"); 8543d21da66SChang Miao return -EINVAL; 8553d21da66SChang Miao } 8563d21da66SChang Miao 8573d21da66SChang Miao for (i = 0; i < key_length / sizeof(cfg->auth_key[0]); i++) 8583d21da66SChang Miao cfg->auth_key[i] = rte_cpu_to_be_32(*key++); 8593d21da66SChang Miao 8603d21da66SChang Miao return 0; 8613d21da66SChang Miao } 8623d21da66SChang Miao 8633d21da66SChang Miao static int 8643d21da66SChang Miao nfp_crypto_msg_build(struct rte_eth_dev *eth_dev, 8653d21da66SChang Miao struct rte_security_session_conf *conf, 8663d21da66SChang Miao struct nfp_ipsec_msg *msg) 8673d21da66SChang Miao { 8683d21da66SChang Miao int ret; 8693d21da66SChang Miao struct ipsec_add_sa *cfg; 8703d21da66SChang Miao struct rte_crypto_sym_xform *cur; 8713d21da66SChang Miao struct rte_crypto_sym_xform *next; 8723d21da66SChang Miao enum rte_security_ipsec_sa_direction direction; 8733d21da66SChang Miao 8743d21da66SChang Miao cur = conf->crypto_xform; 8753d21da66SChang Miao if (cur == NULL) { 8763d21da66SChang Miao PMD_DRV_LOG(ERR, "Unsupported crypto_xform is NULL!"); 8773d21da66SChang Miao return -EINVAL; 8783d21da66SChang Miao } 8793d21da66SChang Miao 8803d21da66SChang Miao next = cur->next; 8813d21da66SChang Miao direction = conf->ipsec.direction; 8823d21da66SChang Miao cfg = &msg->cfg_add_sa; 8833d21da66SChang Miao 8843d21da66SChang Miao switch (cur->type) { 8853d21da66SChang Miao case RTE_CRYPTO_SYM_XFORM_AEAD: 8863d21da66SChang Miao /* Aead transforms can be used for either inbound/outbound IPsec SAs */ 8873d21da66SChang Miao if (next != NULL) { 8883d21da66SChang Miao PMD_DRV_LOG(ERR, "Next crypto_xform type should be NULL!"); 8893d21da66SChang Miao return -EINVAL; 8903d21da66SChang Miao } 8913d21da66SChang Miao 8923d21da66SChang Miao ret = nfp_aead_map(eth_dev, &cur->aead, cur->aead.key.length, cfg); 8933d21da66SChang Miao if (ret < 0) { 8943d21da66SChang Miao PMD_DRV_LOG(ERR, "Failed to map aead alg!"); 8953d21da66SChang Miao return ret; 8963d21da66SChang Miao } 8973d21da66SChang Miao 8983d21da66SChang Miao cfg->aesgcm_fields.salt = rte_cpu_to_be_32(conf->ipsec.salt); 8993d21da66SChang Miao break; 9003d21da66SChang Miao case RTE_CRYPTO_SYM_XFORM_AUTH: 9013d21da66SChang Miao /* Only support Auth + Cipher for inbound */ 9023d21da66SChang Miao if (direction != RTE_SECURITY_IPSEC_SA_DIR_INGRESS) { 9033d21da66SChang Miao PMD_DRV_LOG(ERR, "Direction should be INGRESS, but it is not!"); 9043d21da66SChang Miao return -EINVAL; 9053d21da66SChang Miao } 9063d21da66SChang Miao 9073d21da66SChang Miao if (next == NULL || next->type != RTE_CRYPTO_SYM_XFORM_CIPHER) { 9083d21da66SChang Miao PMD_DRV_LOG(ERR, "Next crypto_xfrm should be cipher, but it is not!"); 9093d21da66SChang Miao return -EINVAL; 9103d21da66SChang Miao } 9113d21da66SChang Miao 9123d21da66SChang Miao ret = nfp_auth_map(eth_dev, &cur->auth, cur->auth.digest_length, cfg); 9133d21da66SChang Miao if (ret < 0) { 9143d21da66SChang Miao PMD_DRV_LOG(ERR, "Failed to map auth alg!"); 9153d21da66SChang Miao return ret; 9163d21da66SChang Miao } 9173d21da66SChang Miao 9183d21da66SChang Miao ret = nfp_cipher_map(eth_dev, &next->cipher, next->cipher.key.length, cfg); 9193d21da66SChang Miao if (ret < 0) { 9203d21da66SChang Miao PMD_DRV_LOG(ERR, "Failed to map cipher alg!"); 9213d21da66SChang Miao return ret; 9223d21da66SChang Miao } 9233d21da66SChang Miao 9243d21da66SChang Miao break; 9253d21da66SChang Miao case RTE_CRYPTO_SYM_XFORM_CIPHER: 9263d21da66SChang Miao /* Only support Cipher + Auth for outbound */ 9273d21da66SChang Miao if (direction != RTE_SECURITY_IPSEC_SA_DIR_EGRESS) { 9283d21da66SChang Miao PMD_DRV_LOG(ERR, "Direction should be EGRESS, but it is not!"); 9293d21da66SChang Miao return -EINVAL; 9303d21da66SChang Miao } 9313d21da66SChang Miao 9323d21da66SChang Miao if (next == NULL || next->type != RTE_CRYPTO_SYM_XFORM_AUTH) { 9333d21da66SChang Miao PMD_DRV_LOG(ERR, "Next crypto_xfrm should be auth, but it is not!"); 9343d21da66SChang Miao return -EINVAL; 9353d21da66SChang Miao } 9363d21da66SChang Miao 9373d21da66SChang Miao ret = nfp_cipher_map(eth_dev, &cur->cipher, cur->cipher.key.length, cfg); 9383d21da66SChang Miao if (ret < 0) { 9393d21da66SChang Miao PMD_DRV_LOG(ERR, "Failed to map cipher alg!"); 9403d21da66SChang Miao return ret; 9413d21da66SChang Miao } 9423d21da66SChang Miao 9433d21da66SChang Miao ret = nfp_auth_map(eth_dev, &next->auth, next->auth.digest_length, cfg); 9443d21da66SChang Miao if (ret < 0) { 9453d21da66SChang Miao PMD_DRV_LOG(ERR, "Failed to map auth alg!"); 9463d21da66SChang Miao return ret; 9473d21da66SChang Miao } 9483d21da66SChang Miao 9493d21da66SChang Miao break; 9503d21da66SChang Miao default: 9513d21da66SChang Miao PMD_DRV_LOG(ERR, "Unsupported crypto_xform type!"); 9523d21da66SChang Miao return -EINVAL; 9533d21da66SChang Miao } 9543d21da66SChang Miao 9553d21da66SChang Miao return 0; 9563d21da66SChang Miao } 9573d21da66SChang Miao 9583d21da66SChang Miao static int 9593d21da66SChang Miao nfp_ipsec_msg_build(struct rte_eth_dev *eth_dev, 9603d21da66SChang Miao struct rte_security_session_conf *conf, 9613d21da66SChang Miao struct nfp_ipsec_msg *msg) 9623d21da66SChang Miao { 9633d21da66SChang Miao int ret; 9643d21da66SChang Miao struct ipsec_add_sa *cfg; 9653d21da66SChang Miao enum rte_security_ipsec_tunnel_type type; 9663d21da66SChang Miao 9673d21da66SChang Miao cfg = &msg->cfg_add_sa; 9683d21da66SChang Miao cfg->spi = conf->ipsec.spi; 9693d21da66SChang Miao cfg->pmtu_limit = 0xffff; 9703d21da66SChang Miao 9713d21da66SChang Miao /* 9723d21da66SChang Miao * UDP encapsulation 9733d21da66SChang Miao * 9743d21da66SChang Miao * 1: Do UDP encapsulation/decapsulation 9753d21da66SChang Miao * 0: No UDP encapsulation 9763d21da66SChang Miao */ 9773d21da66SChang Miao if (conf->ipsec.options.udp_encap == 1) { 9783d21da66SChang Miao cfg->udp_enable = 1; 9793d21da66SChang Miao cfg->natt_dst_port = NFP_UDP_ESP_PORT; 9803d21da66SChang Miao cfg->natt_src_port = NFP_UDP_ESP_PORT; 9813d21da66SChang Miao } 9823d21da66SChang Miao 9833d21da66SChang Miao if (conf->ipsec.options.copy_df == 1) 9843d21da66SChang Miao cfg->df_ctrl = NFP_IPSEC_DF_COPY; 9853d21da66SChang Miao else if (conf->ipsec.tunnel.ipv4.df != 0) 9863d21da66SChang Miao cfg->df_ctrl = NFP_IPSEC_DF_SET; 9873d21da66SChang Miao else 9883d21da66SChang Miao cfg->df_ctrl = NFP_IPSEC_DF_CLEAR; 9893d21da66SChang Miao 9903d21da66SChang Miao switch (conf->action_type) { 9913d21da66SChang Miao case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO: 9923d21da66SChang Miao cfg->ctrl_word.encap_dsbl = 1; 9933d21da66SChang Miao break; 9943d21da66SChang Miao case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL: 9953d21da66SChang Miao cfg->ctrl_word.encap_dsbl = 0; 9963d21da66SChang Miao break; 9973d21da66SChang Miao default: 9983d21da66SChang Miao PMD_DRV_LOG(ERR, "Unsupported IPsec action for offload, action: %d", 9993d21da66SChang Miao conf->action_type); 10003d21da66SChang Miao return -EINVAL; 10013d21da66SChang Miao } 10023d21da66SChang Miao 10033d21da66SChang Miao switch (conf->ipsec.proto) { 10043d21da66SChang Miao case RTE_SECURITY_IPSEC_SA_PROTO_ESP: 10053d21da66SChang Miao cfg->ctrl_word.proto = NFP_IPSEC_PROTOCOL_ESP; 10063d21da66SChang Miao break; 10073d21da66SChang Miao case RTE_SECURITY_IPSEC_SA_PROTO_AH: 10083d21da66SChang Miao cfg->ctrl_word.proto = NFP_IPSEC_PROTOCOL_AH; 10093d21da66SChang Miao break; 10103d21da66SChang Miao default: 10113d21da66SChang Miao PMD_DRV_LOG(ERR, "Unsupported IPsec protocol for offload, protocol: %d", 10123d21da66SChang Miao conf->ipsec.proto); 10133d21da66SChang Miao return -EINVAL; 10143d21da66SChang Miao } 10153d21da66SChang Miao 10163d21da66SChang Miao switch (conf->ipsec.mode) { 10173d21da66SChang Miao case RTE_SECURITY_IPSEC_SA_MODE_TUNNEL: 10183d21da66SChang Miao type = conf->ipsec.tunnel.type; 10193d21da66SChang Miao cfg->ctrl_word.mode = NFP_IPSEC_MODE_TUNNEL; 10203d21da66SChang Miao if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV4) { 10213d21da66SChang Miao cfg->src_ip.v4 = conf->ipsec.tunnel.ipv4.src_ip; 10223d21da66SChang Miao cfg->dst_ip.v4 = conf->ipsec.tunnel.ipv4.dst_ip; 10233d21da66SChang Miao cfg->ipv6 = 0; 10243d21da66SChang Miao } else if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV6) { 10253d21da66SChang Miao cfg->src_ip.v6 = conf->ipsec.tunnel.ipv6.src_addr; 10263d21da66SChang Miao cfg->dst_ip.v6 = conf->ipsec.tunnel.ipv6.dst_addr; 10273d21da66SChang Miao cfg->ipv6 = 1; 10283d21da66SChang Miao } else { 10293d21da66SChang Miao PMD_DRV_LOG(ERR, "Unsupported address family!"); 10303d21da66SChang Miao return -EINVAL; 10313d21da66SChang Miao } 10323d21da66SChang Miao 10333d21da66SChang Miao break; 10343d21da66SChang Miao case RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT: 10353d21da66SChang Miao type = conf->ipsec.tunnel.type; 10363d21da66SChang Miao cfg->ctrl_word.mode = NFP_IPSEC_MODE_TRANSPORT; 10373d21da66SChang Miao if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV4) { 10383d21da66SChang Miao memset(&cfg->src_ip, 0, sizeof(cfg->src_ip)); 10393d21da66SChang Miao cfg->ipv6 = 0; 10403d21da66SChang Miao } else if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV6) { 10413d21da66SChang Miao memset(&cfg->src_ip, 0, sizeof(cfg->src_ip)); 10423d21da66SChang Miao cfg->ipv6 = 1; 10433d21da66SChang Miao } else { 10443d21da66SChang Miao PMD_DRV_LOG(ERR, "Unsupported address family!"); 10453d21da66SChang Miao return -EINVAL; 10463d21da66SChang Miao } 10473d21da66SChang Miao 10483d21da66SChang Miao break; 10493d21da66SChang Miao default: 10503d21da66SChang Miao PMD_DRV_LOG(ERR, "Unsupported IPsec mode for offload, mode: %d", 10513d21da66SChang Miao conf->ipsec.mode); 10523d21da66SChang Miao return -EINVAL; 10533d21da66SChang Miao } 10543d21da66SChang Miao 10553d21da66SChang Miao ret = nfp_crypto_msg_build(eth_dev, conf, msg); 10563d21da66SChang Miao if (ret < 0) { 10573d21da66SChang Miao PMD_DRV_LOG(ERR, "Failed to build auth/crypto/aead msg!"); 10583d21da66SChang Miao return ret; 10593d21da66SChang Miao } 10603d21da66SChang Miao 10613d21da66SChang Miao return 0; 10623d21da66SChang Miao } 10633d21da66SChang Miao 10643d21da66SChang Miao static int 10653d21da66SChang Miao nfp_crypto_create_session(void *device, 10663d21da66SChang Miao struct rte_security_session_conf *conf, 10673d21da66SChang Miao struct rte_security_session *session) 10683d21da66SChang Miao { 10693d21da66SChang Miao int ret; 10703d21da66SChang Miao int sa_idx; 10713d21da66SChang Miao struct nfp_net_hw *hw; 10723d21da66SChang Miao struct nfp_ipsec_msg msg; 10733d21da66SChang Miao struct rte_eth_dev *eth_dev; 10743d21da66SChang Miao struct nfp_ipsec_session *priv_session; 10753d21da66SChang Miao 10763d21da66SChang Miao /* Only support IPsec at present */ 10773d21da66SChang Miao if (conf->protocol != RTE_SECURITY_PROTOCOL_IPSEC) { 10783d21da66SChang Miao PMD_DRV_LOG(ERR, "Unsupported non-IPsec offload!"); 10793d21da66SChang Miao return -EINVAL; 10803d21da66SChang Miao } 10813d21da66SChang Miao 10823d21da66SChang Miao sa_idx = -1; 10833d21da66SChang Miao eth_dev = device; 10843d21da66SChang Miao priv_session = SECURITY_GET_SESS_PRIV(session); 10853d21da66SChang Miao hw = NFP_NET_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); 10863d21da66SChang Miao 10873d21da66SChang Miao if (hw->ipsec_data->sa_free_cnt == 0) { 10883d21da66SChang Miao PMD_DRV_LOG(ERR, "No space in SA table, spi: %d", conf->ipsec.spi); 10893d21da66SChang Miao return -EINVAL; 10903d21da66SChang Miao } 10913d21da66SChang Miao 10923d21da66SChang Miao nfp_get_sa_entry(hw->ipsec_data, &sa_idx); 10933d21da66SChang Miao 10943d21da66SChang Miao if (sa_idx < 0) { 10953d21da66SChang Miao PMD_DRV_LOG(ERR, "Failed to get SA entry!"); 10963d21da66SChang Miao return -EINVAL; 10973d21da66SChang Miao } 10983d21da66SChang Miao 10993d21da66SChang Miao memset(&msg, 0, sizeof(msg)); 11003d21da66SChang Miao ret = nfp_ipsec_msg_build(eth_dev, conf, &msg); 11013d21da66SChang Miao if (ret < 0) { 11023d21da66SChang Miao PMD_DRV_LOG(ERR, "Failed to build IPsec msg!"); 11033d21da66SChang Miao return -EINVAL; 11043d21da66SChang Miao } 11053d21da66SChang Miao 11063d21da66SChang Miao msg.cmd = NFP_IPSEC_CFG_MSG_ADD_SA; 11073d21da66SChang Miao msg.sa_idx = sa_idx; 11083d21da66SChang Miao ret = nfp_ipsec_cfg_cmd_issue(hw, &msg); 11093d21da66SChang Miao if (ret < 0) { 11103d21da66SChang Miao PMD_DRV_LOG(ERR, "Failed to add SA to nic"); 11113d21da66SChang Miao return -EINVAL; 11123d21da66SChang Miao } 11133d21da66SChang Miao 11143d21da66SChang Miao priv_session->action = conf->action_type; 11153d21da66SChang Miao priv_session->ipsec = conf->ipsec; 11163d21da66SChang Miao priv_session->msg = msg.cfg_add_sa; 11173d21da66SChang Miao priv_session->sa_index = sa_idx; 11183d21da66SChang Miao priv_session->dev = eth_dev; 11193d21da66SChang Miao priv_session->user_data = conf->userdata; 11203d21da66SChang Miao 11213d21da66SChang Miao hw->ipsec_data->sa_free_cnt--; 11223d21da66SChang Miao hw->ipsec_data->sa_entries[sa_idx] = priv_session; 11233d21da66SChang Miao 11243d21da66SChang Miao return 0; 11253d21da66SChang Miao } 11263d21da66SChang Miao 11277e6c8063SShihong Wang static int 11287e6c8063SShihong Wang nfp_crypto_update_session(void *device __rte_unused, 11297e6c8063SShihong Wang struct rte_security_session *session, 11307e6c8063SShihong Wang struct rte_security_session_conf *conf) 11317e6c8063SShihong Wang { 11327e6c8063SShihong Wang struct nfp_ipsec_session *priv_session; 11337e6c8063SShihong Wang 11347e6c8063SShihong Wang priv_session = SECURITY_GET_SESS_PRIV(session); 11357e6c8063SShihong Wang if (priv_session == NULL) 11367e6c8063SShihong Wang return -EINVAL; 11377e6c8063SShihong Wang 11387e6c8063SShihong Wang /* Update IPsec ESN value */ 11397e6c8063SShihong Wang if (priv_session->msg.ctrl_word.ext_seq != 0 && conf->ipsec.options.esn != 0) { 11407e6c8063SShihong Wang /* 11417e6c8063SShihong Wang * Store in nfp_ipsec_session for outbound SA for use 11427e6c8063SShihong Wang * in nfp_security_set_pkt_metadata() function. 11437e6c8063SShihong Wang */ 11447e6c8063SShihong Wang priv_session->ipsec.esn.hi = conf->ipsec.esn.hi; 11457e6c8063SShihong Wang priv_session->ipsec.esn.low = conf->ipsec.esn.low; 11467e6c8063SShihong Wang } 11477e6c8063SShihong Wang 11487e6c8063SShihong Wang return 0; 11497e6c8063SShihong Wang } 11507e6c8063SShihong Wang 1151310a1780SShihong Wang static int 1152310a1780SShihong Wang nfp_security_set_pkt_metadata(void *device, 1153310a1780SShihong Wang struct rte_security_session *session, 1154310a1780SShihong Wang struct rte_mbuf *m, 1155310a1780SShihong Wang void *params) 1156310a1780SShihong Wang { 1157310a1780SShihong Wang int offset; 1158310a1780SShihong Wang uint64_t *sqn; 1159310a1780SShihong Wang struct nfp_net_hw *hw; 1160310a1780SShihong Wang struct rte_eth_dev *eth_dev; 1161310a1780SShihong Wang struct nfp_ipsec_session *priv_session; 1162310a1780SShihong Wang 1163310a1780SShihong Wang sqn = params; 1164310a1780SShihong Wang eth_dev = device; 1165310a1780SShihong Wang priv_session = SECURITY_GET_SESS_PRIV(session); 1166310a1780SShihong Wang hw = NFP_NET_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); 1167310a1780SShihong Wang 1168310a1780SShihong Wang if (priv_session->ipsec.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) { 1169310a1780SShihong Wang struct nfp_tx_ipsec_desc_msg *desc_md; 1170310a1780SShihong Wang 1171310a1780SShihong Wang offset = hw->ipsec_data->pkt_dynfield_offset; 1172310a1780SShihong Wang desc_md = RTE_MBUF_DYNFIELD(m, offset, struct nfp_tx_ipsec_desc_msg *); 1173310a1780SShihong Wang 1174310a1780SShihong Wang if (priv_session->msg.ctrl_word.ext_seq != 0 && sqn != NULL) { 1175310a1780SShihong Wang desc_md->esn.low = rte_cpu_to_be_32(*sqn); 1176310a1780SShihong Wang desc_md->esn.hi = rte_cpu_to_be_32(*sqn >> 32); 1177310a1780SShihong Wang } else if (priv_session->msg.ctrl_word.ext_seq != 0) { 1178310a1780SShihong Wang desc_md->esn.low = rte_cpu_to_be_32(priv_session->ipsec.esn.low); 1179310a1780SShihong Wang desc_md->esn.hi = rte_cpu_to_be_32(priv_session->ipsec.esn.hi); 1180310a1780SShihong Wang } else { 1181310a1780SShihong Wang desc_md->esn.low = rte_cpu_to_be_32(priv_session->ipsec.esn.value); 1182310a1780SShihong Wang desc_md->esn.hi = 0; 1183310a1780SShihong Wang } 1184310a1780SShihong Wang 1185310a1780SShihong Wang desc_md->enc = 1; 1186310a1780SShihong Wang desc_md->sa_idx = rte_cpu_to_be_32(priv_session->sa_index); 1187310a1780SShihong Wang } 1188310a1780SShihong Wang 1189310a1780SShihong Wang return 0; 1190310a1780SShihong Wang } 1191310a1780SShihong Wang 11923d21da66SChang Miao /** 11937fb333e9SShihong Wang * Get discards packet statistics for each SA 11947fb333e9SShihong Wang * 11957fb333e9SShihong Wang * The sa_discard_stats contains the statistics of discards packets 11967fb333e9SShihong Wang * of an SA. This function calculates the sum total of discarded packets. 11977fb333e9SShihong Wang * 11987fb333e9SShihong Wang * @param errors 11997fb333e9SShihong Wang * The value is SA discards packet sum total 12007fb333e9SShihong Wang * @param sa_discard_stats 12017fb333e9SShihong Wang * The struct is SA discards packet Statistics 12027fb333e9SShihong Wang */ 12037fb333e9SShihong Wang static void 12047fb333e9SShihong Wang nfp_get_errorstats(uint64_t *errors, 12057fb333e9SShihong Wang struct ipsec_discard_stats *sa_discard_stats) 12067fb333e9SShihong Wang { 12077fb333e9SShihong Wang uint32_t i; 12087fb333e9SShihong Wang uint32_t len; 12097fb333e9SShihong Wang uint32_t *perror; 12107fb333e9SShihong Wang 12117fb333e9SShihong Wang perror = &sa_discard_stats->discards_auth; 12127fb333e9SShihong Wang len = sizeof(struct ipsec_discard_stats) / sizeof(uint32_t); 12137fb333e9SShihong Wang 12147fb333e9SShihong Wang for (i = 0; i < len; i++) 12157fb333e9SShihong Wang *errors += *perror++; 12167fb333e9SShihong Wang 12177fb333e9SShihong Wang *errors -= sa_discard_stats->ipv4_id_counter; 12187fb333e9SShihong Wang } 12197fb333e9SShihong Wang 12207fb333e9SShihong Wang static int 12217fb333e9SShihong Wang nfp_security_session_get_stats(void *device, 12227fb333e9SShihong Wang struct rte_security_session *session, 12237fb333e9SShihong Wang struct rte_security_stats *stats) 12247fb333e9SShihong Wang { 12257fb333e9SShihong Wang int ret; 12267fb333e9SShihong Wang struct nfp_net_hw *hw; 12277fb333e9SShihong Wang struct nfp_ipsec_msg msg; 12287fb333e9SShihong Wang struct rte_eth_dev *eth_dev; 12297fb333e9SShihong Wang struct ipsec_get_sa_stats *cfg_s; 12307fb333e9SShihong Wang struct rte_security_ipsec_stats *ips_s; 12317fb333e9SShihong Wang struct nfp_ipsec_session *priv_session; 12327fb333e9SShihong Wang enum rte_security_ipsec_sa_direction direction; 12337fb333e9SShihong Wang 12347fb333e9SShihong Wang eth_dev = device; 12357fb333e9SShihong Wang priv_session = SECURITY_GET_SESS_PRIV(session); 12367fb333e9SShihong Wang memset(&msg, 0, sizeof(msg)); 12377fb333e9SShihong Wang msg.cmd = NFP_IPSEC_CFG_MSG_GET_SA_STATS; 12387fb333e9SShihong Wang msg.sa_idx = priv_session->sa_index; 12397fb333e9SShihong Wang hw = NFP_NET_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); 12407fb333e9SShihong Wang 12417fb333e9SShihong Wang ret = nfp_ipsec_cfg_cmd_issue(hw, &msg); 12427fb333e9SShihong Wang if (ret < 0) { 12437fb333e9SShihong Wang PMD_DRV_LOG(ERR, "Failed to get SA stats"); 12447fb333e9SShihong Wang return ret; 12457fb333e9SShihong Wang } 12467fb333e9SShihong Wang 12477fb333e9SShihong Wang cfg_s = &msg.cfg_get_stats; 12487fb333e9SShihong Wang direction = priv_session->ipsec.direction; 12497fb333e9SShihong Wang memset(stats, 0, sizeof(struct rte_security_stats)); /* Start with zeros */ 12507fb333e9SShihong Wang stats->protocol = RTE_SECURITY_PROTOCOL_IPSEC; 12517fb333e9SShihong Wang ips_s = &stats->ipsec; 12527fb333e9SShihong Wang 12537fb333e9SShihong Wang /* Only display SA if any counters are non-zero */ 12547fb333e9SShihong Wang if (cfg_s->lifetime_byte_count != 0 || cfg_s->pkt_count != 0) { 12557fb333e9SShihong Wang if (direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) { 12567fb333e9SShihong Wang ips_s->ipackets = cfg_s->pkt_count; 12577fb333e9SShihong Wang ips_s->ibytes = cfg_s->lifetime_byte_count; 12587fb333e9SShihong Wang nfp_get_errorstats(&ips_s->ierrors, &cfg_s->sa_discard_stats); 12597fb333e9SShihong Wang } else { 12607fb333e9SShihong Wang ips_s->opackets = cfg_s->pkt_count; 12617fb333e9SShihong Wang ips_s->obytes = cfg_s->lifetime_byte_count; 12627fb333e9SShihong Wang nfp_get_errorstats(&ips_s->oerrors, &cfg_s->sa_discard_stats); 12637fb333e9SShihong Wang } 12647fb333e9SShihong Wang } 12657fb333e9SShihong Wang 12667fb333e9SShihong Wang return 0; 12677fb333e9SShihong Wang } 12687fb333e9SShihong Wang 1269e6d69ea0SShihong Wang static const struct rte_security_capability * 1270e6d69ea0SShihong Wang nfp_crypto_capabilities_get(void *device __rte_unused) 1271e6d69ea0SShihong Wang { 1272e6d69ea0SShihong Wang return nfp_security_caps; 1273e6d69ea0SShihong Wang } 1274e6d69ea0SShihong Wang 1275e6d69ea0SShihong Wang static uint32_t 1276e6d69ea0SShihong Wang nfp_security_session_get_size(void *device __rte_unused) 1277e6d69ea0SShihong Wang { 1278e6d69ea0SShihong Wang return sizeof(struct nfp_ipsec_session); 1279e6d69ea0SShihong Wang } 1280e6d69ea0SShihong Wang 1281eaf38c9bSShihong Wang static int 1282eaf38c9bSShihong Wang nfp_crypto_remove_sa(struct rte_eth_dev *eth_dev, 1283eaf38c9bSShihong Wang struct nfp_ipsec_session *priv_session) 1284eaf38c9bSShihong Wang { 1285eaf38c9bSShihong Wang int ret; 1286eaf38c9bSShihong Wang uint32_t sa_index; 1287eaf38c9bSShihong Wang struct nfp_net_hw *hw; 1288eaf38c9bSShihong Wang struct nfp_ipsec_msg cfg; 1289eaf38c9bSShihong Wang 1290eaf38c9bSShihong Wang sa_index = priv_session->sa_index; 1291eaf38c9bSShihong Wang hw = NFP_NET_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); 1292eaf38c9bSShihong Wang 1293eaf38c9bSShihong Wang cfg.cmd = NFP_IPSEC_CFG_MSG_INV_SA; 1294eaf38c9bSShihong Wang cfg.sa_idx = sa_index; 1295eaf38c9bSShihong Wang ret = nfp_ipsec_cfg_cmd_issue(hw, &cfg); 1296eaf38c9bSShihong Wang if (ret < 0) { 1297eaf38c9bSShihong Wang PMD_DRV_LOG(ERR, "Failed to remove SA!"); 1298eaf38c9bSShihong Wang return -EINVAL; 1299eaf38c9bSShihong Wang } 1300eaf38c9bSShihong Wang 1301eaf38c9bSShihong Wang hw->ipsec_data->sa_free_cnt++; 1302eaf38c9bSShihong Wang hw->ipsec_data->sa_entries[sa_index] = NULL; 1303eaf38c9bSShihong Wang 1304eaf38c9bSShihong Wang return 0; 1305eaf38c9bSShihong Wang } 1306eaf38c9bSShihong Wang 1307eaf38c9bSShihong Wang static int 1308eaf38c9bSShihong Wang nfp_crypto_remove_session(void *device, 1309eaf38c9bSShihong Wang struct rte_security_session *session) 1310eaf38c9bSShihong Wang { 1311eaf38c9bSShihong Wang int ret; 1312eaf38c9bSShihong Wang struct rte_eth_dev *eth_dev; 1313eaf38c9bSShihong Wang struct nfp_ipsec_session *priv_session; 1314eaf38c9bSShihong Wang 1315eaf38c9bSShihong Wang eth_dev = device; 1316eaf38c9bSShihong Wang priv_session = SECURITY_GET_SESS_PRIV(session); 1317eaf38c9bSShihong Wang if (eth_dev != priv_session->dev) { 1318eaf38c9bSShihong Wang PMD_DRV_LOG(ERR, "Session not bound to this device"); 1319eaf38c9bSShihong Wang return -ENODEV; 1320eaf38c9bSShihong Wang } 1321eaf38c9bSShihong Wang 1322eaf38c9bSShihong Wang ret = nfp_crypto_remove_sa(eth_dev, priv_session); 1323eaf38c9bSShihong Wang if (ret < 0) { 1324eaf38c9bSShihong Wang PMD_DRV_LOG(ERR, "Failed to remove session"); 1325eaf38c9bSShihong Wang return -EFAULT; 1326eaf38c9bSShihong Wang } 1327eaf38c9bSShihong Wang 1328eaf38c9bSShihong Wang memset(priv_session, 0, sizeof(struct nfp_ipsec_session)); 1329eaf38c9bSShihong Wang 1330eaf38c9bSShihong Wang return 0; 1331eaf38c9bSShihong Wang } 1332eaf38c9bSShihong Wang 1333e6d69ea0SShihong Wang static const struct rte_security_ops nfp_security_ops = { 13343d21da66SChang Miao .session_create = nfp_crypto_create_session, 13357e6c8063SShihong Wang .session_update = nfp_crypto_update_session, 1336e6d69ea0SShihong Wang .session_get_size = nfp_security_session_get_size, 13377fb333e9SShihong Wang .session_stats_get = nfp_security_session_get_stats, 1338eaf38c9bSShihong Wang .session_destroy = nfp_crypto_remove_session, 1339310a1780SShihong Wang .set_pkt_metadata = nfp_security_set_pkt_metadata, 1340e6d69ea0SShihong Wang .capabilities_get = nfp_crypto_capabilities_get, 1341e6d69ea0SShihong Wang }; 134254713740SChang Miao 134354713740SChang Miao static int 134454713740SChang Miao nfp_ipsec_ctx_create(struct rte_eth_dev *dev, 134554713740SChang Miao struct nfp_net_ipsec_data *data) 134654713740SChang Miao { 134754713740SChang Miao struct rte_security_ctx *ctx; 134854713740SChang Miao static const struct rte_mbuf_dynfield pkt_md_dynfield = { 134954713740SChang Miao .name = "nfp_ipsec_crypto_pkt_metadata", 135054713740SChang Miao .size = sizeof(struct nfp_tx_ipsec_desc_msg), 135154713740SChang Miao .align = __alignof__(struct nfp_tx_ipsec_desc_msg), 135254713740SChang Miao }; 135354713740SChang Miao 135454713740SChang Miao ctx = rte_zmalloc("security_ctx", 135554713740SChang Miao sizeof(struct rte_security_ctx), 0); 135654713740SChang Miao if (ctx == NULL) { 135754713740SChang Miao PMD_INIT_LOG(ERR, "Failed to malloc security_ctx"); 135854713740SChang Miao return -ENOMEM; 135954713740SChang Miao } 136054713740SChang Miao 136154713740SChang Miao ctx->device = dev; 136254713740SChang Miao ctx->ops = &nfp_security_ops; 136354713740SChang Miao ctx->sess_cnt = 0; 136454713740SChang Miao dev->security_ctx = ctx; 136554713740SChang Miao 136654713740SChang Miao data->pkt_dynfield_offset = rte_mbuf_dynfield_register(&pkt_md_dynfield); 136754713740SChang Miao if (data->pkt_dynfield_offset < 0) { 136854713740SChang Miao PMD_INIT_LOG(ERR, "Failed to register mbuf esn_dynfield"); 136954713740SChang Miao return -ENOMEM; 137054713740SChang Miao } 137154713740SChang Miao 137254713740SChang Miao return 0; 137354713740SChang Miao } 137454713740SChang Miao 137554713740SChang Miao int 137654713740SChang Miao nfp_ipsec_init(struct rte_eth_dev *dev) 137754713740SChang Miao { 137854713740SChang Miao int ret; 137954713740SChang Miao uint32_t cap_extend; 138054713740SChang Miao struct nfp_net_hw *hw; 138154713740SChang Miao struct nfp_net_ipsec_data *data; 138254713740SChang Miao 138354713740SChang Miao hw = NFP_NET_DEV_PRIVATE_TO_HW(dev->data->dev_private); 138454713740SChang Miao 138534f7414bSZerun Fu cap_extend = hw->cap_ext; 138654713740SChang Miao if ((cap_extend & NFP_NET_CFG_CTRL_IPSEC) == 0) { 138754713740SChang Miao PMD_INIT_LOG(INFO, "Unsupported IPsec extend capability"); 138854713740SChang Miao return 0; 138954713740SChang Miao } 139054713740SChang Miao 139154713740SChang Miao data = rte_zmalloc("ipsec_data", sizeof(struct nfp_net_ipsec_data), 0); 139254713740SChang Miao if (data == NULL) { 139354713740SChang Miao PMD_INIT_LOG(ERR, "Failed to malloc ipsec_data"); 139454713740SChang Miao return -ENOMEM; 139554713740SChang Miao } 139654713740SChang Miao 139754713740SChang Miao data->pkt_dynfield_offset = -1; 139854713740SChang Miao data->sa_free_cnt = NFP_NET_IPSEC_MAX_SA_CNT; 139954713740SChang Miao hw->ipsec_data = data; 140054713740SChang Miao 140154713740SChang Miao ret = nfp_ipsec_ctx_create(dev, data); 140254713740SChang Miao if (ret != 0) { 140354713740SChang Miao PMD_INIT_LOG(ERR, "Failed to create IPsec ctx"); 140454713740SChang Miao goto ipsec_cleanup; 140554713740SChang Miao } 140654713740SChang Miao 140754713740SChang Miao return 0; 140854713740SChang Miao 140954713740SChang Miao ipsec_cleanup: 141054713740SChang Miao nfp_ipsec_uninit(dev); 141154713740SChang Miao 141254713740SChang Miao return ret; 141354713740SChang Miao } 141454713740SChang Miao 141554713740SChang Miao static void 141654713740SChang Miao nfp_ipsec_ctx_destroy(struct rte_eth_dev *dev) 141754713740SChang Miao { 141854713740SChang Miao if (dev->security_ctx != NULL) 141954713740SChang Miao rte_free(dev->security_ctx); 142054713740SChang Miao } 142154713740SChang Miao 142254713740SChang Miao void 142354713740SChang Miao nfp_ipsec_uninit(struct rte_eth_dev *dev) 142454713740SChang Miao { 142554713740SChang Miao uint16_t i; 142654713740SChang Miao uint32_t cap_extend; 142754713740SChang Miao struct nfp_net_hw *hw; 142854713740SChang Miao struct nfp_ipsec_session *priv_session; 142954713740SChang Miao 143054713740SChang Miao hw = NFP_NET_DEV_PRIVATE_TO_HW(dev->data->dev_private); 143154713740SChang Miao 143234f7414bSZerun Fu cap_extend = hw->cap_ext; 143354713740SChang Miao if ((cap_extend & NFP_NET_CFG_CTRL_IPSEC) == 0) { 143454713740SChang Miao PMD_INIT_LOG(INFO, "Unsupported IPsec extend capability"); 143554713740SChang Miao return; 143654713740SChang Miao } 143754713740SChang Miao 143854713740SChang Miao nfp_ipsec_ctx_destroy(dev); 143954713740SChang Miao 144054713740SChang Miao if (hw->ipsec_data == NULL) { 144154713740SChang Miao PMD_INIT_LOG(INFO, "IPsec data is NULL!"); 144254713740SChang Miao return; 144354713740SChang Miao } 144454713740SChang Miao 144554713740SChang Miao for (i = 0; i < NFP_NET_IPSEC_MAX_SA_CNT; i++) { 144654713740SChang Miao priv_session = hw->ipsec_data->sa_entries[i]; 144754713740SChang Miao if (priv_session != NULL) 144854713740SChang Miao memset(priv_session, 0, sizeof(struct nfp_ipsec_session)); 144954713740SChang Miao } 145054713740SChang Miao 145154713740SChang Miao rte_free(hw->ipsec_data); 145254713740SChang Miao } 145354713740SChang Miao 1454