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 608966fe7STyler Retzlaff #include <stdalign.h> 708966fe7STyler Retzlaff 854713740SChang Miao #include "nfp_ipsec.h" 954713740SChang Miao 10e6d69ea0SShihong Wang #include <rte_cryptodev.h> 1154713740SChang Miao #include <rte_malloc.h> 1254713740SChang Miao #include <rte_security_driver.h> 1354713740SChang Miao 1454713740SChang Miao #include <ethdev_driver.h> 1554713740SChang Miao #include <ethdev_pci.h> 1654713740SChang Miao 1754713740SChang Miao #include "nfp_logs.h" 1811e9eae4SChaoyong He #include "nfp_net_common.h" 19e2018e37SChaoyong He #include "nfp_net_ctrl.h" 2054713740SChang Miao #include "nfp_rxtx.h" 21ddcd598fSLong Wu #include "nfp_net_meta.h" 2254713740SChang Miao 233d21da66SChang Miao #define NFP_UDP_ESP_PORT 4500 247e13f2dcSShihong Wang #define NFP_ESP_IV_LENGTH 8 253d21da66SChang Miao 26e6d69ea0SShihong Wang static const struct rte_cryptodev_capabilities nfp_crypto_caps[] = { 27e6d69ea0SShihong Wang { 28e6d69ea0SShihong Wang .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC, 29e6d69ea0SShihong Wang .sym = { 30e6d69ea0SShihong Wang .xform_type = RTE_CRYPTO_SYM_XFORM_AUTH, 31e6d69ea0SShihong Wang .auth = { 32e6d69ea0SShihong Wang .algo = RTE_CRYPTO_AUTH_MD5_HMAC, 33e6d69ea0SShihong Wang .block_size = 64, 34e6d69ea0SShihong Wang .key_size = { 35e6d69ea0SShihong Wang .min = 16, 36e6d69ea0SShihong Wang .max = 16, 37e6d69ea0SShihong Wang .increment = 0 38e6d69ea0SShihong Wang }, 39e6d69ea0SShihong Wang .digest_size = { 40e6d69ea0SShihong Wang .min = 12, 41e6d69ea0SShihong Wang .max = 16, 42e6d69ea0SShihong Wang .increment = 4 43e6d69ea0SShihong Wang }, 44e6d69ea0SShihong Wang }, 45e6d69ea0SShihong Wang }, 46e6d69ea0SShihong Wang }, 47e6d69ea0SShihong Wang { 48e6d69ea0SShihong Wang .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC, 49e6d69ea0SShihong Wang .sym = { 50e6d69ea0SShihong Wang .xform_type = RTE_CRYPTO_SYM_XFORM_AUTH, 51e6d69ea0SShihong Wang .auth = { 52e6d69ea0SShihong Wang .algo = RTE_CRYPTO_AUTH_SHA1_HMAC, 53e6d69ea0SShihong Wang .block_size = 64, 54e6d69ea0SShihong Wang .key_size = { 55e6d69ea0SShihong Wang .min = 20, 56e6d69ea0SShihong Wang .max = 64, 57e6d69ea0SShihong Wang .increment = 1 58e6d69ea0SShihong Wang }, 59e6d69ea0SShihong Wang .digest_size = { 60e6d69ea0SShihong Wang .min = 10, 61e6d69ea0SShihong Wang .max = 12, 62e6d69ea0SShihong Wang .increment = 2 63e6d69ea0SShihong Wang }, 64e6d69ea0SShihong Wang }, 65e6d69ea0SShihong Wang }, 66e6d69ea0SShihong Wang }, 67e6d69ea0SShihong Wang { 68e6d69ea0SShihong Wang .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC, 69e6d69ea0SShihong Wang .sym = { 70e6d69ea0SShihong Wang .xform_type = RTE_CRYPTO_SYM_XFORM_AUTH, 71e6d69ea0SShihong Wang .auth = { 72e6d69ea0SShihong Wang .algo = RTE_CRYPTO_AUTH_SHA256_HMAC, 73e6d69ea0SShihong Wang .block_size = 64, 74e6d69ea0SShihong Wang .key_size = { 75e6d69ea0SShihong Wang .min = 32, 76e6d69ea0SShihong Wang .max = 32, 77e6d69ea0SShihong Wang .increment = 0 78e6d69ea0SShihong Wang }, 79e6d69ea0SShihong Wang .digest_size = { 80e6d69ea0SShihong Wang .min = 12, 81e6d69ea0SShihong Wang .max = 16, 82e6d69ea0SShihong Wang .increment = 4 83e6d69ea0SShihong Wang }, 84e6d69ea0SShihong Wang }, 85e6d69ea0SShihong Wang }, 86e6d69ea0SShihong Wang }, 87e6d69ea0SShihong Wang { 88e6d69ea0SShihong Wang .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC, 89e6d69ea0SShihong Wang .sym = { 90e6d69ea0SShihong Wang .xform_type = RTE_CRYPTO_SYM_XFORM_AUTH, 91e6d69ea0SShihong Wang .auth = { 92e6d69ea0SShihong Wang .algo = RTE_CRYPTO_AUTH_SHA384_HMAC, 93e6d69ea0SShihong Wang .block_size = 128, 94e6d69ea0SShihong Wang .key_size = { 95e6d69ea0SShihong Wang .min = 48, 96e6d69ea0SShihong Wang .max = 48, 97e6d69ea0SShihong Wang .increment = 0 98e6d69ea0SShihong Wang }, 99e6d69ea0SShihong Wang .digest_size = { 100e6d69ea0SShihong Wang .min = 12, 101e6d69ea0SShihong Wang .max = 24, 102e6d69ea0SShihong Wang .increment = 12 103e6d69ea0SShihong Wang }, 104e6d69ea0SShihong Wang }, 105e6d69ea0SShihong Wang }, 106e6d69ea0SShihong Wang }, 107e6d69ea0SShihong Wang { 108e6d69ea0SShihong Wang .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC, 109e6d69ea0SShihong Wang .sym = { 110e6d69ea0SShihong Wang .xform_type = RTE_CRYPTO_SYM_XFORM_AUTH, 111e6d69ea0SShihong Wang .auth = { 112e6d69ea0SShihong Wang .algo = RTE_CRYPTO_AUTH_SHA512_HMAC, 113e6d69ea0SShihong Wang .block_size = 128, 114e6d69ea0SShihong Wang .key_size = { 115e6d69ea0SShihong Wang .min = 64, 116e6d69ea0SShihong Wang .max = 64, 117e6d69ea0SShihong Wang .increment = 1 118e6d69ea0SShihong Wang }, 119e6d69ea0SShihong Wang .digest_size = { 120e6d69ea0SShihong Wang .min = 12, 121e6d69ea0SShihong Wang .max = 32, 122e6d69ea0SShihong Wang .increment = 4 123e6d69ea0SShihong Wang }, 124e6d69ea0SShihong Wang }, 125e6d69ea0SShihong Wang }, 126e6d69ea0SShihong Wang }, 127e6d69ea0SShihong Wang { 128e6d69ea0SShihong Wang .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC, 129e6d69ea0SShihong Wang .sym = { 130e6d69ea0SShihong Wang .xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER, 131e6d69ea0SShihong Wang .cipher = { 132e6d69ea0SShihong Wang .algo = RTE_CRYPTO_CIPHER_3DES_CBC, 133e6d69ea0SShihong Wang .block_size = 8, 134e6d69ea0SShihong Wang .key_size = { 135e6d69ea0SShihong Wang .min = 24, 136e6d69ea0SShihong Wang .max = 24, 137e6d69ea0SShihong Wang .increment = 0 138e6d69ea0SShihong Wang }, 139e6d69ea0SShihong Wang .iv_size = { 140e6d69ea0SShihong Wang .min = 8, 141e6d69ea0SShihong Wang .max = 16, 142e6d69ea0SShihong Wang .increment = 8 143e6d69ea0SShihong Wang }, 144e6d69ea0SShihong Wang }, 145e6d69ea0SShihong Wang }, 146e6d69ea0SShihong Wang }, 147e6d69ea0SShihong Wang { 148e6d69ea0SShihong Wang .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC, 149e6d69ea0SShihong Wang .sym = { 150e6d69ea0SShihong Wang .xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER, 151e6d69ea0SShihong Wang .cipher = { 152e6d69ea0SShihong Wang .algo = RTE_CRYPTO_CIPHER_AES_CBC, 153e6d69ea0SShihong Wang .block_size = 16, 154e6d69ea0SShihong Wang .key_size = { 155e6d69ea0SShihong Wang .min = 16, 156e6d69ea0SShihong Wang .max = 32, 157e6d69ea0SShihong Wang .increment = 8 158e6d69ea0SShihong Wang }, 159e6d69ea0SShihong Wang .iv_size = { 160e6d69ea0SShihong Wang .min = 8, 161e6d69ea0SShihong Wang .max = 16, 162e6d69ea0SShihong Wang .increment = 8 163e6d69ea0SShihong Wang }, 164e6d69ea0SShihong Wang }, 165e6d69ea0SShihong Wang }, 166e6d69ea0SShihong Wang }, 167e6d69ea0SShihong Wang { 168e6d69ea0SShihong Wang .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC, 169e6d69ea0SShihong Wang .sym = { 170e6d69ea0SShihong Wang .xform_type = RTE_CRYPTO_SYM_XFORM_AEAD, 171e6d69ea0SShihong Wang .aead = { 172e6d69ea0SShihong Wang .algo = RTE_CRYPTO_AEAD_AES_GCM, 173e6d69ea0SShihong Wang .block_size = 16, 174e6d69ea0SShihong Wang .key_size = { 175e6d69ea0SShihong Wang .min = 16, 176e6d69ea0SShihong Wang .max = 32, 177e6d69ea0SShihong Wang .increment = 8 178e6d69ea0SShihong Wang }, 179e6d69ea0SShihong Wang .digest_size = { 180e6d69ea0SShihong Wang .min = 16, 181e6d69ea0SShihong Wang .max = 16, 182e6d69ea0SShihong Wang .increment = 0 183e6d69ea0SShihong Wang }, 184e6d69ea0SShihong Wang .aad_size = { 185e6d69ea0SShihong Wang .min = 0, 186e6d69ea0SShihong Wang .max = 1024, 187e6d69ea0SShihong Wang .increment = 1 188e6d69ea0SShihong Wang }, 189e6d69ea0SShihong Wang .iv_size = { 190e6d69ea0SShihong Wang .min = 8, 191e6d69ea0SShihong Wang .max = 16, 192e6d69ea0SShihong Wang .increment = 4 193e6d69ea0SShihong Wang } 194e6d69ea0SShihong Wang }, 195e6d69ea0SShihong Wang }, 196e6d69ea0SShihong Wang }, 197e6d69ea0SShihong Wang { 198e6d69ea0SShihong Wang .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC, 199e6d69ea0SShihong Wang .sym = { 200e6d69ea0SShihong Wang .xform_type = RTE_CRYPTO_SYM_XFORM_AEAD, 201e6d69ea0SShihong Wang .aead = { 202e6d69ea0SShihong Wang .algo = RTE_CRYPTO_AEAD_CHACHA20_POLY1305, 203e6d69ea0SShihong Wang .block_size = 16, 204e6d69ea0SShihong Wang .key_size = { 205e6d69ea0SShihong Wang .min = 32, 206e6d69ea0SShihong Wang .max = 32, 207e6d69ea0SShihong Wang .increment = 0 208e6d69ea0SShihong Wang }, 209e6d69ea0SShihong Wang .digest_size = { 210e6d69ea0SShihong Wang .min = 16, 211e6d69ea0SShihong Wang .max = 16, 212e6d69ea0SShihong Wang .increment = 0 213e6d69ea0SShihong Wang }, 214e6d69ea0SShihong Wang .aad_size = { 215e6d69ea0SShihong Wang .min = 0, 216e6d69ea0SShihong Wang .max = 1024, 217e6d69ea0SShihong Wang .increment = 1 218e6d69ea0SShihong Wang }, 219e6d69ea0SShihong Wang .iv_size = { 220e6d69ea0SShihong Wang .min = 8, 221e6d69ea0SShihong Wang .max = 16, 222e6d69ea0SShihong Wang .increment = 4 223e6d69ea0SShihong Wang } 224e6d69ea0SShihong Wang }, 225e6d69ea0SShihong Wang }, 226e6d69ea0SShihong Wang }, 227e6d69ea0SShihong Wang { 228e6d69ea0SShihong Wang .op = RTE_CRYPTO_OP_TYPE_UNDEFINED, 229e6d69ea0SShihong Wang .sym = { 230e6d69ea0SShihong Wang .xform_type = RTE_CRYPTO_SYM_XFORM_NOT_SPECIFIED 231e6d69ea0SShihong Wang }, 232e6d69ea0SShihong Wang } 233e6d69ea0SShihong Wang }; 234e6d69ea0SShihong Wang 235e6d69ea0SShihong Wang static const struct rte_security_capability nfp_security_caps[] = { 236e6d69ea0SShihong Wang { /* IPsec Inline Crypto Tunnel Egress */ 237e6d69ea0SShihong Wang .action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO, 238e6d69ea0SShihong Wang .protocol = RTE_SECURITY_PROTOCOL_IPSEC, 239e6d69ea0SShihong Wang .ipsec = { 240e6d69ea0SShihong Wang .mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL, 241e6d69ea0SShihong Wang .direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS, 242e6d69ea0SShihong Wang .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP, 243e6d69ea0SShihong Wang .options = { 244e6d69ea0SShihong Wang .udp_encap = 1, 245e6d69ea0SShihong Wang .stats = 1, 246e6d69ea0SShihong Wang .esn = 1 247e6d69ea0SShihong Wang } 248e6d69ea0SShihong Wang }, 24968287e9bSShihong Wang .crypto_capabilities = nfp_crypto_caps, 25068287e9bSShihong Wang .ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA 251e6d69ea0SShihong Wang }, 252e6d69ea0SShihong Wang { /* IPsec Inline Crypto Tunnel Ingress */ 253e6d69ea0SShihong Wang .action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO, 254e6d69ea0SShihong Wang .protocol = RTE_SECURITY_PROTOCOL_IPSEC, 255e6d69ea0SShihong Wang .ipsec = { 256e6d69ea0SShihong Wang .mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL, 257e6d69ea0SShihong Wang .direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS, 258e6d69ea0SShihong Wang .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP, 259e6d69ea0SShihong Wang .options = { 260e6d69ea0SShihong Wang .udp_encap = 1, 261e6d69ea0SShihong Wang .stats = 1, 262e6d69ea0SShihong Wang .esn = 1 263e6d69ea0SShihong Wang } 264e6d69ea0SShihong Wang }, 26568287e9bSShihong Wang .crypto_capabilities = nfp_crypto_caps 266e6d69ea0SShihong Wang }, 267e6d69ea0SShihong Wang { /* IPsec Inline Crypto Transport Egress */ 268e6d69ea0SShihong Wang .action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO, 269e6d69ea0SShihong Wang .protocol = RTE_SECURITY_PROTOCOL_IPSEC, 270e6d69ea0SShihong Wang .ipsec = { 271e6d69ea0SShihong Wang .mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT, 272e6d69ea0SShihong Wang .direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS, 273e6d69ea0SShihong Wang .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP, 274e6d69ea0SShihong Wang .options = { 275e6d69ea0SShihong Wang .udp_encap = 1, 276e6d69ea0SShihong Wang .stats = 1, 277e6d69ea0SShihong Wang .esn = 1 278e6d69ea0SShihong Wang } 279e6d69ea0SShihong Wang }, 28068287e9bSShihong Wang .crypto_capabilities = nfp_crypto_caps, 28168287e9bSShihong Wang .ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA 282e6d69ea0SShihong Wang }, 283e6d69ea0SShihong Wang { /* IPsec Inline Crypto Transport Ingress */ 284e6d69ea0SShihong Wang .action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO, 285e6d69ea0SShihong Wang .protocol = RTE_SECURITY_PROTOCOL_IPSEC, 286e6d69ea0SShihong Wang .ipsec = { 287e6d69ea0SShihong Wang .mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT, 288e6d69ea0SShihong Wang .direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS, 289e6d69ea0SShihong Wang .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP, 290e6d69ea0SShihong Wang .options = { 291e6d69ea0SShihong Wang .udp_encap = 1, 292e6d69ea0SShihong Wang .stats = 1, 293e6d69ea0SShihong Wang .esn = 1 294e6d69ea0SShihong Wang } 295e6d69ea0SShihong Wang }, 29668287e9bSShihong Wang .crypto_capabilities = nfp_crypto_caps 297e6d69ea0SShihong Wang }, 298e6d69ea0SShihong Wang { /* IPsec Inline Protocol Tunnel Egress */ 299e6d69ea0SShihong Wang .action = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL, 300e6d69ea0SShihong Wang .protocol = RTE_SECURITY_PROTOCOL_IPSEC, 301e6d69ea0SShihong Wang .ipsec = { 302e6d69ea0SShihong Wang .mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL, 303e6d69ea0SShihong Wang .direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS, 304e6d69ea0SShihong Wang .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP, 305e6d69ea0SShihong Wang .options = { 306e6d69ea0SShihong Wang .udp_encap = 1, 307e6d69ea0SShihong Wang .stats = 1, 308e6d69ea0SShihong Wang .esn = 1 309e6d69ea0SShihong Wang } 310e6d69ea0SShihong Wang }, 31168287e9bSShihong Wang .crypto_capabilities = nfp_crypto_caps, 31268287e9bSShihong Wang .ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA 313e6d69ea0SShihong Wang }, 314e6d69ea0SShihong Wang { /* IPsec Inline Protocol Tunnel Ingress */ 315e6d69ea0SShihong Wang .action = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL, 316e6d69ea0SShihong Wang .protocol = RTE_SECURITY_PROTOCOL_IPSEC, 317e6d69ea0SShihong Wang .ipsec = { 318e6d69ea0SShihong Wang .mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL, 319e6d69ea0SShihong Wang .direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS, 320e6d69ea0SShihong Wang .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP, 321e6d69ea0SShihong Wang .options = { 322e6d69ea0SShihong Wang .udp_encap = 1, 323e6d69ea0SShihong Wang .stats = 1, 324e6d69ea0SShihong Wang .esn = 1 325e6d69ea0SShihong Wang } 326e6d69ea0SShihong Wang }, 32768287e9bSShihong Wang .crypto_capabilities = nfp_crypto_caps 328e6d69ea0SShihong Wang }, 329e6d69ea0SShihong Wang { /* IPsec Inline Protocol Transport Egress */ 330e6d69ea0SShihong Wang .action = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL, 331e6d69ea0SShihong Wang .protocol = RTE_SECURITY_PROTOCOL_IPSEC, 332e6d69ea0SShihong Wang .ipsec = { 333e6d69ea0SShihong Wang .mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT, 334e6d69ea0SShihong Wang .direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS, 335e6d69ea0SShihong Wang .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP, 336e6d69ea0SShihong Wang .options = { 337e6d69ea0SShihong Wang .udp_encap = 1, 338e6d69ea0SShihong Wang .stats = 1, 339e6d69ea0SShihong Wang .esn = 1 340e6d69ea0SShihong Wang } 341e6d69ea0SShihong Wang }, 34268287e9bSShihong Wang .crypto_capabilities = nfp_crypto_caps, 34368287e9bSShihong Wang .ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA 344e6d69ea0SShihong Wang }, 345e6d69ea0SShihong Wang { /* IPsec Inline Protocol Transport Ingress */ 346e6d69ea0SShihong Wang .action = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL, 347e6d69ea0SShihong Wang .protocol = RTE_SECURITY_PROTOCOL_IPSEC, 348e6d69ea0SShihong Wang .ipsec = { 349e6d69ea0SShihong Wang .mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT, 350e6d69ea0SShihong Wang .direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS, 351e6d69ea0SShihong Wang .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP, 352e6d69ea0SShihong Wang .options = { 353e6d69ea0SShihong Wang .udp_encap = 1, 354e6d69ea0SShihong Wang .stats = 1, 355e6d69ea0SShihong Wang .esn = 1 356e6d69ea0SShihong Wang } 357e6d69ea0SShihong Wang }, 35868287e9bSShihong Wang .crypto_capabilities = nfp_crypto_caps 359e6d69ea0SShihong Wang }, 360e6d69ea0SShihong Wang { 361e6d69ea0SShihong Wang .action = RTE_SECURITY_ACTION_TYPE_NONE 362e6d69ea0SShihong Wang } 363e6d69ea0SShihong Wang }; 364e6d69ea0SShihong Wang 3657fb333e9SShihong Wang /* IPsec config message cmd codes */ 3667fb333e9SShihong Wang enum nfp_ipsec_cfg_msg_cmd_codes { 3677fb333e9SShihong Wang NFP_IPSEC_CFG_MSG_ADD_SA, /**< Add a new SA */ 3687fb333e9SShihong Wang NFP_IPSEC_CFG_MSG_INV_SA, /**< Invalidate an existing SA */ 3697fb333e9SShihong Wang NFP_IPSEC_CFG_MSG_MODIFY_SA, /**< Modify an existing SA */ 3707fb333e9SShihong Wang NFP_IPSEC_CFG_MSG_GET_SA_STATS, /**< Report SA counters, flags, etc. */ 3717fb333e9SShihong Wang NFP_IPSEC_CFG_MSG_GET_SEQ_NUMS, /**< Allocate sequence numbers */ 3727fb333e9SShihong Wang NFP_IPSEC_CFG_MSG_LAST 3737fb333e9SShihong Wang }; 3747fb333e9SShihong Wang 3757fb333e9SShihong Wang enum nfp_ipsec_cfg_msg_rsp_codes { 3767fb333e9SShihong Wang NFP_IPSEC_CFG_MSG_OK, 3777fb333e9SShihong Wang NFP_IPSEC_CFG_MSG_FAILED, 3787fb333e9SShihong Wang NFP_IPSEC_CFG_MSG_SA_VALID, 3797fb333e9SShihong Wang NFP_IPSEC_CFG_MSG_SA_HASH_ADD_FAILED, 3807fb333e9SShihong Wang NFP_IPSEC_CFG_MSG_SA_HASH_DEL_FAILED, 3817fb333e9SShihong Wang NFP_IPSEC_CFG_MSG_SA_INVALID_CMD 3827fb333e9SShihong Wang }; 3837fb333e9SShihong Wang 3843d21da66SChang Miao enum nfp_ipsec_mode { 3853d21da66SChang Miao NFP_IPSEC_MODE_TRANSPORT, 3863d21da66SChang Miao NFP_IPSEC_MODE_TUNNEL, 3873d21da66SChang Miao }; 3883d21da66SChang Miao 3893d21da66SChang Miao enum nfp_ipsec_protocol { 3903d21da66SChang Miao NFP_IPSEC_PROTOCOL_AH, 3913d21da66SChang Miao NFP_IPSEC_PROTOCOL_ESP, 3923d21da66SChang Miao }; 3933d21da66SChang Miao 3943d21da66SChang Miao /* Cipher modes */ 3953d21da66SChang Miao enum nfp_ipsec_cimode { 3963d21da66SChang Miao NFP_IPSEC_CIMODE_ECB, 3973d21da66SChang Miao NFP_IPSEC_CIMODE_CBC, 3983d21da66SChang Miao NFP_IPSEC_CIMODE_CFB, 3993d21da66SChang Miao NFP_IPSEC_CIMODE_OFB, 4003d21da66SChang Miao NFP_IPSEC_CIMODE_CTR, 4013d21da66SChang Miao }; 4023d21da66SChang Miao 4033d21da66SChang Miao /* Hash types */ 4043d21da66SChang Miao enum nfp_ipsec_hash_type { 4053d21da66SChang Miao NFP_IPSEC_HASH_NONE, 4063d21da66SChang Miao NFP_IPSEC_HASH_MD5_96, 4073d21da66SChang Miao NFP_IPSEC_HASH_SHA1_96, 4083d21da66SChang Miao NFP_IPSEC_HASH_SHA256_96, 4093d21da66SChang Miao NFP_IPSEC_HASH_SHA384_96, 4103d21da66SChang Miao NFP_IPSEC_HASH_SHA512_96, 4113d21da66SChang Miao NFP_IPSEC_HASH_MD5_128, 4123d21da66SChang Miao NFP_IPSEC_HASH_SHA1_80, 4133d21da66SChang Miao NFP_IPSEC_HASH_SHA256_128, 4143d21da66SChang Miao NFP_IPSEC_HASH_SHA384_192, 4153d21da66SChang Miao NFP_IPSEC_HASH_SHA512_256, 4163d21da66SChang Miao NFP_IPSEC_HASH_GF128_128, 4173d21da66SChang Miao NFP_IPSEC_HASH_POLY1305_128, 4183d21da66SChang Miao }; 4193d21da66SChang Miao 4203d21da66SChang Miao /* Cipher types */ 4213d21da66SChang Miao enum nfp_ipsec_cipher_type { 4223d21da66SChang Miao NFP_IPSEC_CIPHER_NULL, 4233d21da66SChang Miao NFP_IPSEC_CIPHER_3DES, 4243d21da66SChang Miao NFP_IPSEC_CIPHER_AES128, 4253d21da66SChang Miao NFP_IPSEC_CIPHER_AES192, 4263d21da66SChang Miao NFP_IPSEC_CIPHER_AES256, 4273d21da66SChang Miao NFP_IPSEC_CIPHER_AES128_NULL, 4283d21da66SChang Miao NFP_IPSEC_CIPHER_AES192_NULL, 4293d21da66SChang Miao NFP_IPSEC_CIPHER_AES256_NULL, 4303d21da66SChang Miao NFP_IPSEC_CIPHER_CHACHA20, 4313d21da66SChang Miao }; 4323d21da66SChang Miao 4333d21da66SChang Miao /* Don't Fragment types */ 4343d21da66SChang Miao enum nfp_ipsec_df_type { 4353d21da66SChang Miao NFP_IPSEC_DF_CLEAR, 4363d21da66SChang Miao NFP_IPSEC_DF_SET, 4373d21da66SChang Miao NFP_IPSEC_DF_COPY, 4383d21da66SChang Miao }; 4393d21da66SChang Miao 4407fb333e9SShihong Wang static int 4414a9bb682SChaoyong He nfp_ipsec_cfg_cmd_issue(struct nfp_net_hw *net_hw, 4427fb333e9SShihong Wang struct nfp_ipsec_msg *msg) 4437fb333e9SShihong Wang { 4447fb333e9SShihong Wang int ret; 4457fb333e9SShihong Wang uint32_t i; 4467fb333e9SShihong Wang uint32_t msg_size; 4477fb333e9SShihong Wang 4487fb333e9SShihong Wang msg_size = RTE_DIM(msg->raw); 4497fb333e9SShihong Wang msg->rsp = NFP_IPSEC_CFG_MSG_OK; 4507fb333e9SShihong Wang 4517fb333e9SShihong Wang for (i = 0; i < msg_size; i++) 4524a9bb682SChaoyong He nn_cfg_writel(&net_hw->super, NFP_NET_CFG_MBOX_VAL + 4 * i, msg->raw[i]); 4537fb333e9SShihong Wang 4544a9bb682SChaoyong He ret = nfp_net_mbox_reconfig(net_hw, NFP_NET_CFG_MBOX_CMD_IPSEC); 4557fb333e9SShihong Wang if (ret < 0) { 456*b6de4353SZerun Fu PMD_DRV_LOG(ERR, "Failed to IPsec reconfig mbox."); 4577fb333e9SShihong Wang return ret; 4587fb333e9SShihong Wang } 4597fb333e9SShihong Wang 4607fb333e9SShihong Wang /* 4617fb333e9SShihong Wang * Not all commands and callers make use of response message data. But 4627fb333e9SShihong Wang * leave this up to the caller and always read and store the full 4637fb333e9SShihong Wang * response. One example where the data is needed is for statistics. 4647fb333e9SShihong Wang */ 4657fb333e9SShihong Wang for (i = 0; i < msg_size; i++) 4664a9bb682SChaoyong He msg->raw[i] = nn_cfg_readl(&net_hw->super, NFP_NET_CFG_MBOX_VAL + 4 * i); 4677fb333e9SShihong Wang 4687fb333e9SShihong Wang switch (msg->rsp) { 4697fb333e9SShihong Wang case NFP_IPSEC_CFG_MSG_OK: 4707fb333e9SShihong Wang ret = 0; 4717fb333e9SShihong Wang break; 4727fb333e9SShihong Wang case NFP_IPSEC_CFG_MSG_SA_INVALID_CMD: 4737fb333e9SShihong Wang ret = -EINVAL; 4747fb333e9SShihong Wang break; 4757fb333e9SShihong Wang case NFP_IPSEC_CFG_MSG_SA_VALID: 4767fb333e9SShihong Wang ret = -EEXIST; 4777fb333e9SShihong Wang break; 4787fb333e9SShihong Wang case NFP_IPSEC_CFG_MSG_FAILED: 4797fb333e9SShihong Wang /* FALLTHROUGH */ 4807fb333e9SShihong Wang case NFP_IPSEC_CFG_MSG_SA_HASH_ADD_FAILED: 4817fb333e9SShihong Wang /* FALLTHROUGH */ 4827fb333e9SShihong Wang case NFP_IPSEC_CFG_MSG_SA_HASH_DEL_FAILED: 4837fb333e9SShihong Wang ret = -EIO; 4847fb333e9SShihong Wang break; 4857fb333e9SShihong Wang default: 4867fb333e9SShihong Wang ret = -EDOM; 4877fb333e9SShihong Wang } 4887fb333e9SShihong Wang 4897fb333e9SShihong Wang return ret; 4907fb333e9SShihong Wang } 4917fb333e9SShihong Wang 4927fb333e9SShihong Wang /** 4933d21da66SChang Miao * Get valid SA index from SA table 4943d21da66SChang Miao * 4953d21da66SChang Miao * @param data 4963d21da66SChang Miao * SA table pointer 4973d21da66SChang Miao * @param sa_idx 4983d21da66SChang Miao * SA table index pointer 4993d21da66SChang Miao * 5003d21da66SChang Miao * @return 5013d21da66SChang Miao * Negative number on full or repeat, 0 on success 5023d21da66SChang Miao * 5033d21da66SChang Miao * Note: multiple sockets may create same SA session. 5043d21da66SChang Miao */ 5053d21da66SChang Miao static void 5063d21da66SChang Miao nfp_get_sa_entry(struct nfp_net_ipsec_data *data, 5073d21da66SChang Miao int *sa_idx) 5083d21da66SChang Miao { 5093d21da66SChang Miao uint32_t i; 5103d21da66SChang Miao 5113d21da66SChang Miao for (i = 0; i < NFP_NET_IPSEC_MAX_SA_CNT; i++) { 5123d21da66SChang Miao if (data->sa_entries[i] == NULL) { 5133d21da66SChang Miao *sa_idx = i; 5143d21da66SChang Miao break; 5153d21da66SChang Miao } 5163d21da66SChang Miao } 5173d21da66SChang Miao } 5183d21da66SChang Miao 5193d21da66SChang Miao static void 5203d21da66SChang Miao nfp_aesgcm_iv_update(struct ipsec_add_sa *cfg, 5213d21da66SChang Miao uint16_t iv_len, 5223d21da66SChang Miao const char *iv_string) 5233d21da66SChang Miao { 5243d21da66SChang Miao int i; 5253d21da66SChang Miao char *save; 5263d21da66SChang Miao char *iv_b; 5273d21da66SChang Miao char *iv_str; 5287e13f2dcSShihong Wang const rte_be32_t *iv_value; 52977cb4714SChaoyong He uint8_t cfg_iv[NFP_ESP_IV_LENGTH] = {}; 5303d21da66SChang Miao 5313d21da66SChang Miao iv_str = strdup(iv_string); 5324ea9eeb6SChengwen Feng if (iv_str == NULL) { 533*b6de4353SZerun Fu PMD_DRV_LOG(ERR, "Failed to strdup iv_string."); 5344ea9eeb6SChengwen Feng return; 5354ea9eeb6SChengwen Feng } 5364ea9eeb6SChengwen Feng 5373d21da66SChang Miao for (i = 0; i < iv_len; i++) { 5383d21da66SChang Miao iv_b = strtok_r(i ? NULL : iv_str, ",", &save); 5393d21da66SChang Miao if (iv_b == NULL) 5403d21da66SChang Miao break; 5413d21da66SChang Miao 5423d21da66SChang Miao cfg_iv[i] = strtoul(iv_b, NULL, 0); 5433d21da66SChang Miao } 5443d21da66SChang Miao 5457e13f2dcSShihong Wang iv_value = (const rte_be32_t *)(cfg_iv); 5467e13f2dcSShihong Wang cfg->aesgcm_fields.iv[0] = rte_be_to_cpu_32(iv_value[0]); 5477e13f2dcSShihong Wang cfg->aesgcm_fields.iv[1] = rte_be_to_cpu_32(iv_value[1]); 5483d21da66SChang Miao 5493d21da66SChang Miao free(iv_str); 5503d21da66SChang Miao } 5513d21da66SChang Miao 5523d21da66SChang Miao static int 5533d21da66SChang Miao set_aes_keylen(uint32_t key_length, 5543d21da66SChang Miao struct ipsec_add_sa *cfg) 5553d21da66SChang Miao { 5563d21da66SChang Miao switch (key_length << 3) { 5573d21da66SChang Miao case 128: 5583d21da66SChang Miao cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_AES128; 5593d21da66SChang Miao break; 5603d21da66SChang Miao case 192: 5613d21da66SChang Miao cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_AES192; 5623d21da66SChang Miao break; 5633d21da66SChang Miao case 256: 5643d21da66SChang Miao cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_AES256; 5653d21da66SChang Miao break; 5663d21da66SChang Miao default: 5673d21da66SChang Miao PMD_DRV_LOG(ERR, "AES cipher key length is illegal!"); 5683d21da66SChang Miao return -EINVAL; 5693d21da66SChang Miao } 5703d21da66SChang Miao 5713d21da66SChang Miao return 0; 5723d21da66SChang Miao } 5733d21da66SChang Miao 5743d21da66SChang Miao /* Map rte_security_session_conf aead algo to NFP aead algo */ 5753d21da66SChang Miao static int 5763d21da66SChang Miao nfp_aead_map(struct rte_eth_dev *eth_dev, 5773d21da66SChang Miao struct rte_crypto_aead_xform *aead, 5783d21da66SChang Miao uint32_t key_length, 5793d21da66SChang Miao struct ipsec_add_sa *cfg) 5803d21da66SChang Miao { 5813d21da66SChang Miao int ret; 5823d21da66SChang Miao uint32_t i; 5833d21da66SChang Miao uint32_t index; 5843d21da66SChang Miao uint16_t iv_len; 5853d21da66SChang Miao uint32_t offset; 5863d21da66SChang Miao uint32_t device_id; 5873d21da66SChang Miao const char *iv_str; 5887e13f2dcSShihong Wang const rte_be32_t *key; 5894a9bb682SChaoyong He struct nfp_net_hw *net_hw; 5903d21da66SChang Miao 5919d723baaSChaoyong He net_hw = eth_dev->data->dev_private; 5924a9bb682SChaoyong He device_id = net_hw->device_id; 5933d21da66SChang Miao offset = 0; 5943d21da66SChang Miao 5953d21da66SChang Miao switch (aead->algo) { 5963d21da66SChang Miao case RTE_CRYPTO_AEAD_AES_GCM: 5973d21da66SChang Miao if (aead->digest_length != 16) { 5983d21da66SChang Miao PMD_DRV_LOG(ERR, "ICV must be 128bit with RTE_CRYPTO_AEAD_AES_GCM!"); 5993d21da66SChang Miao return -EINVAL; 6003d21da66SChang Miao } 6013d21da66SChang Miao 6023d21da66SChang Miao cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CTR; 6033d21da66SChang Miao cfg->ctrl_word.hash = NFP_IPSEC_HASH_GF128_128; 6043d21da66SChang Miao 6053d21da66SChang Miao ret = set_aes_keylen(key_length, cfg); 6063d21da66SChang Miao if (ret < 0) { 6073d21da66SChang Miao PMD_DRV_LOG(ERR, "Failed to set AES_GCM key length!"); 6083d21da66SChang Miao return -EINVAL; 6093d21da66SChang Miao } 6103d21da66SChang Miao 6113d21da66SChang Miao break; 6123d21da66SChang Miao case RTE_CRYPTO_AEAD_CHACHA20_POLY1305: 6133d21da66SChang Miao if (device_id != PCI_DEVICE_ID_NFP3800_PF_NIC) { 6143d21da66SChang Miao PMD_DRV_LOG(ERR, "Unsupported aead CHACHA20_POLY1305 algorithm!"); 6153d21da66SChang Miao return -EINVAL; 6163d21da66SChang Miao } 6173d21da66SChang Miao 6183d21da66SChang Miao if (aead->digest_length != 16) { 619*b6de4353SZerun Fu PMD_DRV_LOG(ERR, "ICV must be 128bit with RTE_CRYPTO_AEAD_CHACHA20_POLY1305."); 6203d21da66SChang Miao return -EINVAL; 6213d21da66SChang Miao } 6223d21da66SChang Miao 6233d21da66SChang Miao /* Aead->alg_key_len includes 32-bit salt */ 6243d21da66SChang Miao if (key_length != 32) { 625*b6de4353SZerun Fu PMD_DRV_LOG(ERR, "Unsupported CHACHA20 key length."); 6263d21da66SChang Miao return -EINVAL; 6273d21da66SChang Miao } 6283d21da66SChang Miao 6293d21da66SChang Miao /* The CHACHA20's mode is not configured */ 6303d21da66SChang Miao cfg->ctrl_word.hash = NFP_IPSEC_HASH_POLY1305_128; 6313d21da66SChang Miao cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_CHACHA20; 6323d21da66SChang Miao break; 6333d21da66SChang Miao default: 6343d21da66SChang Miao PMD_DRV_LOG(ERR, "Unsupported aead algorithm!"); 6353d21da66SChang Miao return -EINVAL; 6363d21da66SChang Miao } 6373d21da66SChang Miao 6387e13f2dcSShihong Wang key = (const rte_be32_t *)(aead->key.data); 6393d21da66SChang Miao 6403d21da66SChang Miao /* 6413d21da66SChang Miao * The CHACHA20's key order needs to be adjusted based on hardware design. 6423d21da66SChang Miao * Unadjusted order: {K0, K1, K2, K3, K4, K5, K6, K7} 6433d21da66SChang Miao * Adjusted order: {K4, K5, K6, K7, K0, K1, K2, K3} 6443d21da66SChang Miao */ 6453d21da66SChang Miao if (aead->algo == RTE_CRYPTO_AEAD_CHACHA20_POLY1305) 6463d21da66SChang Miao offset = key_length / sizeof(cfg->cipher_key[0]) << 1; 6473d21da66SChang Miao 6483d21da66SChang Miao for (i = 0; i < key_length / sizeof(cfg->cipher_key[0]); i++) { 6493d21da66SChang Miao index = (i + offset) % (key_length / sizeof(cfg->cipher_key[0])); 6507e13f2dcSShihong Wang cfg->cipher_key[index] = rte_be_to_cpu_32(key[i]); 6513d21da66SChang Miao } 6523d21da66SChang Miao 6533d21da66SChang Miao /* 6547e13f2dcSShihong Wang * The iv of the FW is equal to ESN by default. Only the 6557e13f2dcSShihong Wang * aead algorithm can offload the iv of configuration and 6567e13f2dcSShihong Wang * the length of iv cannot be greater than NFP_ESP_IV_LENGTH. 6573d21da66SChang Miao */ 6583d21da66SChang Miao iv_str = getenv("ETH_SEC_IV_OVR"); 6593d21da66SChang Miao if (iv_str != NULL) { 6603d21da66SChang Miao iv_len = aead->iv.length; 6617e13f2dcSShihong Wang if (iv_len > NFP_ESP_IV_LENGTH) { 662*b6de4353SZerun Fu PMD_DRV_LOG(ERR, "Unsupported length of iv data."); 6637e13f2dcSShihong Wang return -EINVAL; 6647e13f2dcSShihong Wang } 6657e13f2dcSShihong Wang 6663d21da66SChang Miao nfp_aesgcm_iv_update(cfg, iv_len, iv_str); 6673d21da66SChang Miao } 6683d21da66SChang Miao 6693d21da66SChang Miao return 0; 6703d21da66SChang Miao } 6713d21da66SChang Miao 6723d21da66SChang Miao /* Map rte_security_session_conf cipher algo to NFP cipher algo */ 6733d21da66SChang Miao static int 6743d21da66SChang Miao nfp_cipher_map(struct rte_eth_dev *eth_dev, 6753d21da66SChang Miao struct rte_crypto_cipher_xform *cipher, 6763d21da66SChang Miao uint32_t key_length, 6773d21da66SChang Miao struct ipsec_add_sa *cfg) 6783d21da66SChang Miao { 6793d21da66SChang Miao int ret; 6803d21da66SChang Miao uint32_t i; 6813d21da66SChang Miao uint32_t device_id; 6827e13f2dcSShihong Wang const rte_be32_t *key; 6834a9bb682SChaoyong He struct nfp_net_hw *net_hw; 6843d21da66SChang Miao 6859d723baaSChaoyong He net_hw = eth_dev->data->dev_private; 6864a9bb682SChaoyong He device_id = net_hw->device_id; 6873d21da66SChang Miao 6883d21da66SChang Miao switch (cipher->algo) { 6893d21da66SChang Miao case RTE_CRYPTO_CIPHER_NULL: 6903d21da66SChang Miao cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CBC; 6913d21da66SChang Miao cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_NULL; 6923d21da66SChang Miao break; 6933d21da66SChang Miao case RTE_CRYPTO_CIPHER_3DES_CBC: 6943d21da66SChang Miao if (device_id == PCI_DEVICE_ID_NFP3800_PF_NIC) { 6953d21da66SChang Miao PMD_DRV_LOG(ERR, "Unsupported 3DESCBC encryption algorithm!"); 6963d21da66SChang Miao return -EINVAL; 6973d21da66SChang Miao } 6983d21da66SChang Miao 6993d21da66SChang Miao cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CBC; 7003d21da66SChang Miao cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_3DES; 7013d21da66SChang Miao break; 7023d21da66SChang Miao case RTE_CRYPTO_CIPHER_AES_CBC: 7033d21da66SChang Miao cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CBC; 7043d21da66SChang Miao ret = set_aes_keylen(key_length, cfg); 7053d21da66SChang Miao if (ret < 0) { 7063d21da66SChang Miao PMD_DRV_LOG(ERR, "Failed to set cipher key length!"); 7073d21da66SChang Miao return -EINVAL; 7083d21da66SChang Miao } 7093d21da66SChang Miao 7103d21da66SChang Miao break; 7113d21da66SChang Miao default: 7123d21da66SChang Miao PMD_DRV_LOG(ERR, "Unsupported cipher alg!"); 7133d21da66SChang Miao return -EINVAL; 7143d21da66SChang Miao } 7153d21da66SChang Miao 7167e13f2dcSShihong Wang key = (const rte_be32_t *)(cipher->key.data); 7173d21da66SChang Miao if (key_length > sizeof(cfg->cipher_key)) { 718*b6de4353SZerun Fu PMD_DRV_LOG(ERR, "Insufficient space for offloaded key."); 7193d21da66SChang Miao return -EINVAL; 7203d21da66SChang Miao } 7213d21da66SChang Miao 7223d21da66SChang Miao for (i = 0; i < key_length / sizeof(cfg->cipher_key[0]); i++) 7237e13f2dcSShihong Wang cfg->cipher_key[i] = rte_be_to_cpu_32(key[i]); 7243d21da66SChang Miao 7253d21da66SChang Miao return 0; 7263d21da66SChang Miao } 7273d21da66SChang Miao 7283d21da66SChang Miao static void 7293d21da66SChang Miao set_md5hmac(struct ipsec_add_sa *cfg, 7303d21da66SChang Miao uint32_t *digest_length) 7313d21da66SChang Miao { 7323d21da66SChang Miao switch (*digest_length) { 7333d21da66SChang Miao case 96: 7343d21da66SChang Miao cfg->ctrl_word.hash = NFP_IPSEC_HASH_MD5_96; 7353d21da66SChang Miao break; 7363d21da66SChang Miao case 128: 7373d21da66SChang Miao cfg->ctrl_word.hash = NFP_IPSEC_HASH_MD5_128; 7383d21da66SChang Miao break; 7393d21da66SChang Miao default: 7403d21da66SChang Miao *digest_length = 0; 7413d21da66SChang Miao } 7423d21da66SChang Miao } 7433d21da66SChang Miao 7443d21da66SChang Miao static void 7453d21da66SChang Miao set_sha1hmac(struct ipsec_add_sa *cfg, 7463d21da66SChang Miao uint32_t *digest_length) 7473d21da66SChang Miao { 7483d21da66SChang Miao switch (*digest_length) { 7493d21da66SChang Miao case 96: 7503d21da66SChang Miao cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA1_96; 7513d21da66SChang Miao break; 7523d21da66SChang Miao case 80: 7533d21da66SChang Miao cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA1_80; 7543d21da66SChang Miao break; 7553d21da66SChang Miao default: 7563d21da66SChang Miao *digest_length = 0; 7573d21da66SChang Miao } 7583d21da66SChang Miao } 7593d21da66SChang Miao 7603d21da66SChang Miao static void 7613d21da66SChang Miao set_sha2_256hmac(struct ipsec_add_sa *cfg, 7623d21da66SChang Miao uint32_t *digest_length) 7633d21da66SChang Miao { 7643d21da66SChang Miao switch (*digest_length) { 7653d21da66SChang Miao case 96: 7663d21da66SChang Miao cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA256_96; 7673d21da66SChang Miao break; 7683d21da66SChang Miao case 128: 7693d21da66SChang Miao cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA256_128; 7703d21da66SChang Miao break; 7713d21da66SChang Miao default: 7723d21da66SChang Miao *digest_length = 0; 7733d21da66SChang Miao } 7743d21da66SChang Miao } 7753d21da66SChang Miao 7763d21da66SChang Miao static void 7773d21da66SChang Miao set_sha2_384hmac(struct ipsec_add_sa *cfg, 7783d21da66SChang Miao uint32_t *digest_length) 7793d21da66SChang Miao { 7803d21da66SChang Miao switch (*digest_length) { 7813d21da66SChang Miao case 96: 7823d21da66SChang Miao cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA384_96; 7833d21da66SChang Miao break; 7843d21da66SChang Miao case 192: 7853d21da66SChang Miao cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA384_192; 7863d21da66SChang Miao break; 7873d21da66SChang Miao default: 7883d21da66SChang Miao *digest_length = 0; 7893d21da66SChang Miao } 7903d21da66SChang Miao } 7913d21da66SChang Miao 7923d21da66SChang Miao static void 7933d21da66SChang Miao set_sha2_512hmac(struct ipsec_add_sa *cfg, 7943d21da66SChang Miao uint32_t *digest_length) 7953d21da66SChang Miao { 7963d21da66SChang Miao switch (*digest_length) { 7973d21da66SChang Miao case 96: 7983d21da66SChang Miao cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA512_96; 7993d21da66SChang Miao break; 8003d21da66SChang Miao case 256: 8013d21da66SChang Miao cfg->ctrl_word.hash = NFP_IPSEC_HASH_SHA512_256; 8023d21da66SChang Miao break; 8033d21da66SChang Miao default: 8043d21da66SChang Miao *digest_length = 0; 8053d21da66SChang Miao } 8063d21da66SChang Miao } 8073d21da66SChang Miao 8083d21da66SChang Miao /* Map rte_security_session_conf auth algo to NFP auth algo */ 8093d21da66SChang Miao static int 8103d21da66SChang Miao nfp_auth_map(struct rte_eth_dev *eth_dev, 8113d21da66SChang Miao struct rte_crypto_auth_xform *auth, 8123d21da66SChang Miao uint32_t digest_length, 8133d21da66SChang Miao struct ipsec_add_sa *cfg) 8143d21da66SChang Miao { 8153d21da66SChang Miao uint32_t i; 8163d21da66SChang Miao uint8_t key_length; 8173d21da66SChang Miao uint32_t device_id; 8187e13f2dcSShihong Wang const rte_be32_t *key; 8194a9bb682SChaoyong He struct nfp_net_hw *net_hw; 8203d21da66SChang Miao 8213d21da66SChang Miao if (digest_length == 0) { 8223d21da66SChang Miao PMD_DRV_LOG(ERR, "Auth digest length is illegal!"); 8233d21da66SChang Miao return -EINVAL; 8243d21da66SChang Miao } 8253d21da66SChang Miao 8269d723baaSChaoyong He net_hw = eth_dev->data->dev_private; 8274a9bb682SChaoyong He device_id = net_hw->device_id; 8283d21da66SChang Miao digest_length = digest_length << 3; 8293d21da66SChang Miao 8303d21da66SChang Miao switch (auth->algo) { 8313d21da66SChang Miao case RTE_CRYPTO_AUTH_NULL: 8323d21da66SChang Miao cfg->ctrl_word.hash = NFP_IPSEC_HASH_NONE; 8333d21da66SChang Miao digest_length = 1; 8343d21da66SChang Miao break; 8353d21da66SChang Miao case RTE_CRYPTO_AUTH_MD5_HMAC: 8363d21da66SChang Miao if (device_id == PCI_DEVICE_ID_NFP3800_PF_NIC) { 8373d21da66SChang Miao PMD_DRV_LOG(ERR, "Unsupported MD5HMAC authentication algorithm!"); 8383d21da66SChang Miao return -EINVAL; 8393d21da66SChang Miao } 8403d21da66SChang Miao 8413d21da66SChang Miao set_md5hmac(cfg, &digest_length); 8423d21da66SChang Miao break; 8433d21da66SChang Miao case RTE_CRYPTO_AUTH_SHA1_HMAC: 8443d21da66SChang Miao set_sha1hmac(cfg, &digest_length); 8453d21da66SChang Miao break; 8463d21da66SChang Miao case RTE_CRYPTO_AUTH_SHA256_HMAC: 8473d21da66SChang Miao set_sha2_256hmac(cfg, &digest_length); 8483d21da66SChang Miao break; 8493d21da66SChang Miao case RTE_CRYPTO_AUTH_SHA384_HMAC: 8503d21da66SChang Miao set_sha2_384hmac(cfg, &digest_length); 8513d21da66SChang Miao break; 8523d21da66SChang Miao case RTE_CRYPTO_AUTH_SHA512_HMAC: 8533d21da66SChang Miao set_sha2_512hmac(cfg, &digest_length); 8543d21da66SChang Miao break; 8553d21da66SChang Miao default: 8563d21da66SChang Miao PMD_DRV_LOG(ERR, "Unsupported auth alg!"); 8573d21da66SChang Miao return -EINVAL; 8583d21da66SChang Miao } 8593d21da66SChang Miao 8603d21da66SChang Miao if (digest_length == 0) { 861*b6de4353SZerun Fu PMD_DRV_LOG(ERR, "Unsupported authentication algorithm digest length."); 8623d21da66SChang Miao return -EINVAL; 8633d21da66SChang Miao } 8643d21da66SChang Miao 8657e13f2dcSShihong Wang key = (const rte_be32_t *)(auth->key.data); 8663d21da66SChang Miao key_length = auth->key.length; 8673d21da66SChang Miao if (key_length > sizeof(cfg->auth_key)) { 8683d21da66SChang Miao PMD_DRV_LOG(ERR, "Insufficient space for offloaded auth key!"); 8693d21da66SChang Miao return -EINVAL; 8703d21da66SChang Miao } 8713d21da66SChang Miao 8723d21da66SChang Miao for (i = 0; i < key_length / sizeof(cfg->auth_key[0]); i++) 8737e13f2dcSShihong Wang cfg->auth_key[i] = rte_be_to_cpu_32(key[i]); 8743d21da66SChang Miao 8753d21da66SChang Miao return 0; 8763d21da66SChang Miao } 8773d21da66SChang Miao 8783d21da66SChang Miao static int 8793d21da66SChang Miao nfp_crypto_msg_build(struct rte_eth_dev *eth_dev, 8803d21da66SChang Miao struct rte_security_session_conf *conf, 8813d21da66SChang Miao struct nfp_ipsec_msg *msg) 8823d21da66SChang Miao { 8833d21da66SChang Miao int ret; 8843d21da66SChang Miao struct ipsec_add_sa *cfg; 8853d21da66SChang Miao struct rte_crypto_sym_xform *cur; 8863d21da66SChang Miao struct rte_crypto_sym_xform *next; 8873d21da66SChang Miao enum rte_security_ipsec_sa_direction direction; 8883d21da66SChang Miao 8893d21da66SChang Miao cur = conf->crypto_xform; 8903d21da66SChang Miao if (cur == NULL) { 8913d21da66SChang Miao PMD_DRV_LOG(ERR, "Unsupported crypto_xform is NULL!"); 8923d21da66SChang Miao return -EINVAL; 8933d21da66SChang Miao } 8943d21da66SChang Miao 8953d21da66SChang Miao next = cur->next; 8963d21da66SChang Miao direction = conf->ipsec.direction; 8973d21da66SChang Miao cfg = &msg->cfg_add_sa; 8983d21da66SChang Miao 8993d21da66SChang Miao switch (cur->type) { 9003d21da66SChang Miao case RTE_CRYPTO_SYM_XFORM_AEAD: 9013d21da66SChang Miao /* Aead transforms can be used for either inbound/outbound IPsec SAs */ 9023d21da66SChang Miao if (next != NULL) { 9033d21da66SChang Miao PMD_DRV_LOG(ERR, "Next crypto_xform type should be NULL!"); 9043d21da66SChang Miao return -EINVAL; 9053d21da66SChang Miao } 9063d21da66SChang Miao 9073d21da66SChang Miao ret = nfp_aead_map(eth_dev, &cur->aead, cur->aead.key.length, cfg); 9083d21da66SChang Miao if (ret < 0) { 9093d21da66SChang Miao PMD_DRV_LOG(ERR, "Failed to map aead alg!"); 9103d21da66SChang Miao return ret; 9113d21da66SChang Miao } 9123d21da66SChang Miao 9137e13f2dcSShihong Wang cfg->aesgcm_fields.salt = conf->ipsec.salt; 9143d21da66SChang Miao break; 9153d21da66SChang Miao case RTE_CRYPTO_SYM_XFORM_AUTH: 9163d21da66SChang Miao /* Only support Auth + Cipher for inbound */ 9173d21da66SChang Miao if (direction != RTE_SECURITY_IPSEC_SA_DIR_INGRESS) { 9183d21da66SChang Miao PMD_DRV_LOG(ERR, "Direction should be INGRESS, but it is not!"); 9193d21da66SChang Miao return -EINVAL; 9203d21da66SChang Miao } 9213d21da66SChang Miao 9223d21da66SChang Miao if (next == NULL || next->type != RTE_CRYPTO_SYM_XFORM_CIPHER) { 9233d21da66SChang Miao PMD_DRV_LOG(ERR, "Next crypto_xfrm should be cipher, but it is not!"); 9243d21da66SChang Miao return -EINVAL; 9253d21da66SChang Miao } 9263d21da66SChang Miao 9273d21da66SChang Miao ret = nfp_auth_map(eth_dev, &cur->auth, cur->auth.digest_length, cfg); 9283d21da66SChang Miao if (ret < 0) { 9293d21da66SChang Miao PMD_DRV_LOG(ERR, "Failed to map auth alg!"); 9303d21da66SChang Miao return ret; 9313d21da66SChang Miao } 9323d21da66SChang Miao 9333d21da66SChang Miao ret = nfp_cipher_map(eth_dev, &next->cipher, next->cipher.key.length, cfg); 9343d21da66SChang Miao if (ret < 0) { 9353d21da66SChang Miao PMD_DRV_LOG(ERR, "Failed to map cipher alg!"); 9363d21da66SChang Miao return ret; 9373d21da66SChang Miao } 9383d21da66SChang Miao 9393d21da66SChang Miao break; 9403d21da66SChang Miao case RTE_CRYPTO_SYM_XFORM_CIPHER: 9413d21da66SChang Miao /* Only support Cipher + Auth for outbound */ 9423d21da66SChang Miao if (direction != RTE_SECURITY_IPSEC_SA_DIR_EGRESS) { 9433d21da66SChang Miao PMD_DRV_LOG(ERR, "Direction should be EGRESS, but it is not!"); 9443d21da66SChang Miao return -EINVAL; 9453d21da66SChang Miao } 9463d21da66SChang Miao 9473d21da66SChang Miao if (next == NULL || next->type != RTE_CRYPTO_SYM_XFORM_AUTH) { 9483d21da66SChang Miao PMD_DRV_LOG(ERR, "Next crypto_xfrm should be auth, but it is not!"); 9493d21da66SChang Miao return -EINVAL; 9503d21da66SChang Miao } 9513d21da66SChang Miao 9523d21da66SChang Miao ret = nfp_cipher_map(eth_dev, &cur->cipher, cur->cipher.key.length, cfg); 9533d21da66SChang Miao if (ret < 0) { 9543d21da66SChang Miao PMD_DRV_LOG(ERR, "Failed to map cipher alg!"); 9553d21da66SChang Miao return ret; 9563d21da66SChang Miao } 9573d21da66SChang Miao 9583d21da66SChang Miao ret = nfp_auth_map(eth_dev, &next->auth, next->auth.digest_length, cfg); 9593d21da66SChang Miao if (ret < 0) { 9603d21da66SChang Miao PMD_DRV_LOG(ERR, "Failed to map auth alg!"); 9613d21da66SChang Miao return ret; 9623d21da66SChang Miao } 9633d21da66SChang Miao 9643d21da66SChang Miao break; 9653d21da66SChang Miao default: 9663d21da66SChang Miao PMD_DRV_LOG(ERR, "Unsupported crypto_xform type!"); 9673d21da66SChang Miao return -EINVAL; 9683d21da66SChang Miao } 9693d21da66SChang Miao 9703d21da66SChang Miao return 0; 9713d21da66SChang Miao } 9723d21da66SChang Miao 9733d21da66SChang Miao static int 9743d21da66SChang Miao nfp_ipsec_msg_build(struct rte_eth_dev *eth_dev, 9753d21da66SChang Miao struct rte_security_session_conf *conf, 9763d21da66SChang Miao struct nfp_ipsec_msg *msg) 9773d21da66SChang Miao { 9787e13f2dcSShihong Wang int i; 9793d21da66SChang Miao int ret; 9807e13f2dcSShihong Wang rte_be32_t *src_ip; 9817e13f2dcSShihong Wang rte_be32_t *dst_ip; 9823d21da66SChang Miao struct ipsec_add_sa *cfg; 9833d21da66SChang Miao enum rte_security_ipsec_tunnel_type type; 9843d21da66SChang Miao 9853d21da66SChang Miao cfg = &msg->cfg_add_sa; 9863d21da66SChang Miao cfg->spi = conf->ipsec.spi; 9873d21da66SChang Miao cfg->pmtu_limit = 0xffff; 9883d21da66SChang Miao 9893d21da66SChang Miao /* 9903d21da66SChang Miao * UDP encapsulation 9913d21da66SChang Miao * 9923d21da66SChang Miao * 1: Do UDP encapsulation/decapsulation 9933d21da66SChang Miao * 0: No UDP encapsulation 9943d21da66SChang Miao */ 9953d21da66SChang Miao if (conf->ipsec.options.udp_encap == 1) { 9963d21da66SChang Miao cfg->udp_enable = 1; 9973d21da66SChang Miao cfg->natt_dst_port = NFP_UDP_ESP_PORT; 9983d21da66SChang Miao cfg->natt_src_port = NFP_UDP_ESP_PORT; 9993d21da66SChang Miao } 10003d21da66SChang Miao 10013d21da66SChang Miao if (conf->ipsec.options.copy_df == 1) 10023d21da66SChang Miao cfg->df_ctrl = NFP_IPSEC_DF_COPY; 10033d21da66SChang Miao else if (conf->ipsec.tunnel.ipv4.df != 0) 10043d21da66SChang Miao cfg->df_ctrl = NFP_IPSEC_DF_SET; 10053d21da66SChang Miao else 10063d21da66SChang Miao cfg->df_ctrl = NFP_IPSEC_DF_CLEAR; 10073d21da66SChang Miao 10083d21da66SChang Miao switch (conf->action_type) { 10093d21da66SChang Miao case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO: 10103d21da66SChang Miao cfg->ctrl_word.encap_dsbl = 1; 10113d21da66SChang Miao break; 10123d21da66SChang Miao case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL: 10133d21da66SChang Miao cfg->ctrl_word.encap_dsbl = 0; 10143d21da66SChang Miao break; 10153d21da66SChang Miao default: 1016*b6de4353SZerun Fu PMD_DRV_LOG(ERR, "Unsupported IPsec action for offload, action: %d.", 10173d21da66SChang Miao conf->action_type); 10183d21da66SChang Miao return -EINVAL; 10193d21da66SChang Miao } 10203d21da66SChang Miao 10213d21da66SChang Miao switch (conf->ipsec.proto) { 10223d21da66SChang Miao case RTE_SECURITY_IPSEC_SA_PROTO_ESP: 10233d21da66SChang Miao cfg->ctrl_word.proto = NFP_IPSEC_PROTOCOL_ESP; 10243d21da66SChang Miao break; 10253d21da66SChang Miao case RTE_SECURITY_IPSEC_SA_PROTO_AH: 10263d21da66SChang Miao cfg->ctrl_word.proto = NFP_IPSEC_PROTOCOL_AH; 10273d21da66SChang Miao break; 10283d21da66SChang Miao default: 1029*b6de4353SZerun Fu PMD_DRV_LOG(ERR, "Unsupported IPsec protocol for offload, protocol: %d.", 10303d21da66SChang Miao conf->ipsec.proto); 10313d21da66SChang Miao return -EINVAL; 10323d21da66SChang Miao } 10333d21da66SChang Miao 10343d21da66SChang Miao switch (conf->ipsec.mode) { 10353d21da66SChang Miao case RTE_SECURITY_IPSEC_SA_MODE_TUNNEL: 10363d21da66SChang Miao type = conf->ipsec.tunnel.type; 10373d21da66SChang Miao cfg->ctrl_word.mode = NFP_IPSEC_MODE_TUNNEL; 10383d21da66SChang Miao if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV4) { 10397e13f2dcSShihong Wang src_ip = (rte_be32_t *)&conf->ipsec.tunnel.ipv4.src_ip.s_addr; 10407e13f2dcSShihong Wang dst_ip = (rte_be32_t *)&conf->ipsec.tunnel.ipv4.dst_ip.s_addr; 10417e13f2dcSShihong Wang cfg->src_ip[0] = rte_be_to_cpu_32(src_ip[0]); 10427e13f2dcSShihong Wang cfg->dst_ip[0] = rte_be_to_cpu_32(dst_ip[0]); 10433d21da66SChang Miao cfg->ipv6 = 0; 10443d21da66SChang Miao } else if (type == RTE_SECURITY_IPSEC_TUNNEL_IPV6) { 10452ede1422SRobin Jarry src_ip = (rte_be32_t *)&conf->ipsec.tunnel.ipv6.src_addr; 10462ede1422SRobin Jarry dst_ip = (rte_be32_t *)&conf->ipsec.tunnel.ipv6.dst_addr; 10477e13f2dcSShihong Wang for (i = 0; i < 4; i++) { 10487e13f2dcSShihong Wang cfg->src_ip[i] = rte_be_to_cpu_32(src_ip[i]); 10497e13f2dcSShihong Wang cfg->dst_ip[i] = rte_be_to_cpu_32(dst_ip[i]); 10507e13f2dcSShihong Wang } 10513d21da66SChang Miao cfg->ipv6 = 1; 10523d21da66SChang Miao } else { 10533d21da66SChang Miao PMD_DRV_LOG(ERR, "Unsupported address family!"); 10543d21da66SChang Miao return -EINVAL; 10553d21da66SChang Miao } 10563d21da66SChang Miao 10573d21da66SChang Miao break; 10583d21da66SChang Miao case RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT: 10593d21da66SChang Miao cfg->ctrl_word.mode = NFP_IPSEC_MODE_TRANSPORT; 10603d21da66SChang Miao memset(&cfg->src_ip, 0, sizeof(cfg->src_ip)); 10617e13f2dcSShihong Wang memset(&cfg->dst_ip, 0, sizeof(cfg->dst_ip)); 10623d21da66SChang Miao 10633d21da66SChang Miao break; 10643d21da66SChang Miao default: 1065*b6de4353SZerun Fu PMD_DRV_LOG(ERR, "Unsupported IPsec mode for offload, mode: %d.", 10663d21da66SChang Miao conf->ipsec.mode); 10673d21da66SChang Miao return -EINVAL; 10683d21da66SChang Miao } 10693d21da66SChang Miao 10703d21da66SChang Miao ret = nfp_crypto_msg_build(eth_dev, conf, msg); 10713d21da66SChang Miao if (ret < 0) { 10723d21da66SChang Miao PMD_DRV_LOG(ERR, "Failed to build auth/crypto/aead msg!"); 10733d21da66SChang Miao return ret; 10743d21da66SChang Miao } 10753d21da66SChang Miao 10763d21da66SChang Miao return 0; 10773d21da66SChang Miao } 10783d21da66SChang Miao 10793d21da66SChang Miao static int 10803d21da66SChang Miao nfp_crypto_create_session(void *device, 10813d21da66SChang Miao struct rte_security_session_conf *conf, 10823d21da66SChang Miao struct rte_security_session *session) 10833d21da66SChang Miao { 10843d21da66SChang Miao int ret; 10853d21da66SChang Miao int sa_idx; 10864a9bb682SChaoyong He struct nfp_net_hw *net_hw; 10873d21da66SChang Miao struct nfp_ipsec_msg msg; 10883d21da66SChang Miao struct rte_eth_dev *eth_dev; 10893d21da66SChang Miao struct nfp_ipsec_session *priv_session; 10903d21da66SChang Miao 10913d21da66SChang Miao /* Only support IPsec at present */ 10923d21da66SChang Miao if (conf->protocol != RTE_SECURITY_PROTOCOL_IPSEC) { 10933d21da66SChang Miao PMD_DRV_LOG(ERR, "Unsupported non-IPsec offload!"); 10943d21da66SChang Miao return -EINVAL; 10953d21da66SChang Miao } 10963d21da66SChang Miao 10973d21da66SChang Miao sa_idx = -1; 10983d21da66SChang Miao eth_dev = device; 10993d21da66SChang Miao priv_session = SECURITY_GET_SESS_PRIV(session); 11009d723baaSChaoyong He net_hw = eth_dev->data->dev_private; 11013d21da66SChang Miao 11024a9bb682SChaoyong He if (net_hw->ipsec_data->sa_free_cnt == 0) { 1103*b6de4353SZerun Fu PMD_DRV_LOG(ERR, "No space in SA table, spi: %d.", conf->ipsec.spi); 11043d21da66SChang Miao return -EINVAL; 11053d21da66SChang Miao } 11063d21da66SChang Miao 11074a9bb682SChaoyong He nfp_get_sa_entry(net_hw->ipsec_data, &sa_idx); 11083d21da66SChang Miao 11093d21da66SChang Miao if (sa_idx < 0) { 11103d21da66SChang Miao PMD_DRV_LOG(ERR, "Failed to get SA entry!"); 11113d21da66SChang Miao return -EINVAL; 11123d21da66SChang Miao } 11133d21da66SChang Miao 11143d21da66SChang Miao memset(&msg, 0, sizeof(msg)); 11153d21da66SChang Miao ret = nfp_ipsec_msg_build(eth_dev, conf, &msg); 11163d21da66SChang Miao if (ret < 0) { 11173d21da66SChang Miao PMD_DRV_LOG(ERR, "Failed to build IPsec msg!"); 11183d21da66SChang Miao return -EINVAL; 11193d21da66SChang Miao } 11203d21da66SChang Miao 11213d21da66SChang Miao msg.cmd = NFP_IPSEC_CFG_MSG_ADD_SA; 11223d21da66SChang Miao msg.sa_idx = sa_idx; 11234a9bb682SChaoyong He ret = nfp_ipsec_cfg_cmd_issue(net_hw, &msg); 11243d21da66SChang Miao if (ret < 0) { 1125*b6de4353SZerun Fu PMD_DRV_LOG(ERR, "Failed to add SA to nic."); 11263d21da66SChang Miao return -EINVAL; 11273d21da66SChang Miao } 11283d21da66SChang Miao 11293d21da66SChang Miao priv_session->action = conf->action_type; 11303d21da66SChang Miao priv_session->ipsec = conf->ipsec; 11313d21da66SChang Miao priv_session->msg = msg.cfg_add_sa; 11323d21da66SChang Miao priv_session->sa_index = sa_idx; 11333d21da66SChang Miao priv_session->dev = eth_dev; 11343d21da66SChang Miao priv_session->user_data = conf->userdata; 11353d21da66SChang Miao 11364a9bb682SChaoyong He net_hw->ipsec_data->sa_free_cnt--; 11374a9bb682SChaoyong He net_hw->ipsec_data->sa_entries[sa_idx] = priv_session; 11383d21da66SChang Miao 11393d21da66SChang Miao return 0; 11403d21da66SChang Miao } 11413d21da66SChang Miao 11427e6c8063SShihong Wang static int 11437e6c8063SShihong Wang nfp_crypto_update_session(void *device __rte_unused, 11447e6c8063SShihong Wang struct rte_security_session *session, 11457e6c8063SShihong Wang struct rte_security_session_conf *conf) 11467e6c8063SShihong Wang { 11477e6c8063SShihong Wang struct nfp_ipsec_session *priv_session; 11487e6c8063SShihong Wang 11497e6c8063SShihong Wang priv_session = SECURITY_GET_SESS_PRIV(session); 11507e6c8063SShihong Wang if (priv_session == NULL) 11517e6c8063SShihong Wang return -EINVAL; 11527e6c8063SShihong Wang 11537e6c8063SShihong Wang /* Update IPsec ESN value */ 11547e6c8063SShihong Wang if (priv_session->msg.ctrl_word.ext_seq != 0 && conf->ipsec.options.esn != 0) { 11557e6c8063SShihong Wang /* 11567e6c8063SShihong Wang * Store in nfp_ipsec_session for outbound SA for use 11577e6c8063SShihong Wang * in nfp_security_set_pkt_metadata() function. 11587e6c8063SShihong Wang */ 11597e6c8063SShihong Wang priv_session->ipsec.esn.hi = conf->ipsec.esn.hi; 11607e6c8063SShihong Wang priv_session->ipsec.esn.low = conf->ipsec.esn.low; 11617e6c8063SShihong Wang } 11627e6c8063SShihong Wang 11637e6c8063SShihong Wang return 0; 11647e6c8063SShihong Wang } 11657e6c8063SShihong Wang 1166310a1780SShihong Wang static int 1167310a1780SShihong Wang nfp_security_set_pkt_metadata(void *device, 1168310a1780SShihong Wang struct rte_security_session *session, 1169310a1780SShihong Wang struct rte_mbuf *m, 1170310a1780SShihong Wang void *params) 1171310a1780SShihong Wang { 1172310a1780SShihong Wang int offset; 1173310a1780SShihong Wang uint64_t *sqn; 11744a9bb682SChaoyong He struct nfp_net_hw *net_hw; 1175310a1780SShihong Wang struct rte_eth_dev *eth_dev; 1176310a1780SShihong Wang struct nfp_ipsec_session *priv_session; 1177310a1780SShihong Wang 1178310a1780SShihong Wang sqn = params; 1179310a1780SShihong Wang eth_dev = device; 1180310a1780SShihong Wang priv_session = SECURITY_GET_SESS_PRIV(session); 11819d723baaSChaoyong He net_hw = eth_dev->data->dev_private; 1182310a1780SShihong Wang 1183310a1780SShihong Wang if (priv_session->ipsec.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) { 1184310a1780SShihong Wang struct nfp_tx_ipsec_desc_msg *desc_md; 1185310a1780SShihong Wang 11864a9bb682SChaoyong He offset = net_hw->ipsec_data->pkt_dynfield_offset; 1187310a1780SShihong Wang desc_md = RTE_MBUF_DYNFIELD(m, offset, struct nfp_tx_ipsec_desc_msg *); 1188310a1780SShihong Wang 1189310a1780SShihong Wang if (priv_session->msg.ctrl_word.ext_seq != 0 && sqn != NULL) { 11907e13f2dcSShihong Wang desc_md->esn.low = (uint32_t)*sqn; 11917e13f2dcSShihong Wang desc_md->esn.hi = (uint32_t)(*sqn >> 32); 1192310a1780SShihong Wang } else if (priv_session->msg.ctrl_word.ext_seq != 0) { 11937e13f2dcSShihong Wang desc_md->esn.low = priv_session->ipsec.esn.low; 11947e13f2dcSShihong Wang desc_md->esn.hi = priv_session->ipsec.esn.hi; 1195310a1780SShihong Wang } else { 11967e13f2dcSShihong Wang desc_md->esn.low = priv_session->ipsec.esn.low; 1197310a1780SShihong Wang desc_md->esn.hi = 0; 1198310a1780SShihong Wang } 1199310a1780SShihong Wang 1200310a1780SShihong Wang desc_md->enc = 1; 12017e13f2dcSShihong Wang desc_md->sa_idx = priv_session->sa_index; 1202310a1780SShihong Wang } 1203310a1780SShihong Wang 1204310a1780SShihong Wang return 0; 1205310a1780SShihong Wang } 1206310a1780SShihong Wang 12073d21da66SChang Miao /** 12087fb333e9SShihong Wang * Get discards packet statistics for each SA 12097fb333e9SShihong Wang * 12107fb333e9SShihong Wang * The sa_discard_stats contains the statistics of discards packets 12117fb333e9SShihong Wang * of an SA. This function calculates the sum total of discarded packets. 12127fb333e9SShihong Wang * 12137fb333e9SShihong Wang * @param errors 12147fb333e9SShihong Wang * The value is SA discards packet sum total 12157fb333e9SShihong Wang * @param sa_discard_stats 12167fb333e9SShihong Wang * The struct is SA discards packet Statistics 12177fb333e9SShihong Wang */ 12187fb333e9SShihong Wang static void 12197fb333e9SShihong Wang nfp_get_errorstats(uint64_t *errors, 12207fb333e9SShihong Wang struct ipsec_discard_stats *sa_discard_stats) 12217fb333e9SShihong Wang { 12227fb333e9SShihong Wang uint32_t i; 12237fb333e9SShihong Wang uint32_t len; 12247fb333e9SShihong Wang uint32_t *perror; 12257fb333e9SShihong Wang 12267fb333e9SShihong Wang perror = &sa_discard_stats->discards_auth; 12277fb333e9SShihong Wang len = sizeof(struct ipsec_discard_stats) / sizeof(uint32_t); 12287fb333e9SShihong Wang 12297fb333e9SShihong Wang for (i = 0; i < len; i++) 12307fb333e9SShihong Wang *errors += *perror++; 12317fb333e9SShihong Wang 12327fb333e9SShihong Wang *errors -= sa_discard_stats->ipv4_id_counter; 12337fb333e9SShihong Wang } 12347fb333e9SShihong Wang 12357fb333e9SShihong Wang static int 12367fb333e9SShihong Wang nfp_security_session_get_stats(void *device, 12377fb333e9SShihong Wang struct rte_security_session *session, 12387fb333e9SShihong Wang struct rte_security_stats *stats) 12397fb333e9SShihong Wang { 12407fb333e9SShihong Wang int ret; 12414a9bb682SChaoyong He struct nfp_net_hw *net_hw; 12427fb333e9SShihong Wang struct nfp_ipsec_msg msg; 12437fb333e9SShihong Wang struct rte_eth_dev *eth_dev; 12447fb333e9SShihong Wang struct ipsec_get_sa_stats *cfg_s; 12457fb333e9SShihong Wang struct rte_security_ipsec_stats *ips_s; 12467fb333e9SShihong Wang struct nfp_ipsec_session *priv_session; 12477fb333e9SShihong Wang enum rte_security_ipsec_sa_direction direction; 12487fb333e9SShihong Wang 12497fb333e9SShihong Wang eth_dev = device; 12507fb333e9SShihong Wang priv_session = SECURITY_GET_SESS_PRIV(session); 12517fb333e9SShihong Wang memset(&msg, 0, sizeof(msg)); 12527fb333e9SShihong Wang msg.cmd = NFP_IPSEC_CFG_MSG_GET_SA_STATS; 12537fb333e9SShihong Wang msg.sa_idx = priv_session->sa_index; 12549d723baaSChaoyong He net_hw = eth_dev->data->dev_private; 12557fb333e9SShihong Wang 12564a9bb682SChaoyong He ret = nfp_ipsec_cfg_cmd_issue(net_hw, &msg); 12577fb333e9SShihong Wang if (ret < 0) { 1258*b6de4353SZerun Fu PMD_DRV_LOG(ERR, "Failed to get SA stats."); 12597fb333e9SShihong Wang return ret; 12607fb333e9SShihong Wang } 12617fb333e9SShihong Wang 12627fb333e9SShihong Wang cfg_s = &msg.cfg_get_stats; 12637fb333e9SShihong Wang direction = priv_session->ipsec.direction; 12647fb333e9SShihong Wang memset(stats, 0, sizeof(struct rte_security_stats)); /* Start with zeros */ 12657fb333e9SShihong Wang stats->protocol = RTE_SECURITY_PROTOCOL_IPSEC; 12667fb333e9SShihong Wang ips_s = &stats->ipsec; 12677fb333e9SShihong Wang 12687fb333e9SShihong Wang /* Only display SA if any counters are non-zero */ 12697fb333e9SShihong Wang if (cfg_s->lifetime_byte_count != 0 || cfg_s->pkt_count != 0) { 12707fb333e9SShihong Wang if (direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) { 12717fb333e9SShihong Wang ips_s->ipackets = cfg_s->pkt_count; 12727fb333e9SShihong Wang ips_s->ibytes = cfg_s->lifetime_byte_count; 12737fb333e9SShihong Wang nfp_get_errorstats(&ips_s->ierrors, &cfg_s->sa_discard_stats); 12747fb333e9SShihong Wang } else { 12757fb333e9SShihong Wang ips_s->opackets = cfg_s->pkt_count; 12767fb333e9SShihong Wang ips_s->obytes = cfg_s->lifetime_byte_count; 12777fb333e9SShihong Wang nfp_get_errorstats(&ips_s->oerrors, &cfg_s->sa_discard_stats); 12787fb333e9SShihong Wang } 12797fb333e9SShihong Wang } 12807fb333e9SShihong Wang 12817fb333e9SShihong Wang return 0; 12827fb333e9SShihong Wang } 12837fb333e9SShihong Wang 1284e6d69ea0SShihong Wang static const struct rte_security_capability * 1285e6d69ea0SShihong Wang nfp_crypto_capabilities_get(void *device __rte_unused) 1286e6d69ea0SShihong Wang { 1287e6d69ea0SShihong Wang return nfp_security_caps; 1288e6d69ea0SShihong Wang } 1289e6d69ea0SShihong Wang 1290e6d69ea0SShihong Wang static uint32_t 1291e6d69ea0SShihong Wang nfp_security_session_get_size(void *device __rte_unused) 1292e6d69ea0SShihong Wang { 1293e6d69ea0SShihong Wang return sizeof(struct nfp_ipsec_session); 1294e6d69ea0SShihong Wang } 1295e6d69ea0SShihong Wang 1296eaf38c9bSShihong Wang static int 1297eaf38c9bSShihong Wang nfp_crypto_remove_sa(struct rte_eth_dev *eth_dev, 1298eaf38c9bSShihong Wang struct nfp_ipsec_session *priv_session) 1299eaf38c9bSShihong Wang { 1300eaf38c9bSShihong Wang int ret; 1301eaf38c9bSShihong Wang uint32_t sa_index; 13024a9bb682SChaoyong He struct nfp_net_hw *net_hw; 1303eaf38c9bSShihong Wang struct nfp_ipsec_msg cfg; 1304eaf38c9bSShihong Wang 1305eaf38c9bSShihong Wang sa_index = priv_session->sa_index; 13069d723baaSChaoyong He net_hw = eth_dev->data->dev_private; 1307eaf38c9bSShihong Wang 1308eaf38c9bSShihong Wang cfg.cmd = NFP_IPSEC_CFG_MSG_INV_SA; 1309eaf38c9bSShihong Wang cfg.sa_idx = sa_index; 13104a9bb682SChaoyong He ret = nfp_ipsec_cfg_cmd_issue(net_hw, &cfg); 1311eaf38c9bSShihong Wang if (ret < 0) { 1312eaf38c9bSShihong Wang PMD_DRV_LOG(ERR, "Failed to remove SA!"); 1313eaf38c9bSShihong Wang return -EINVAL; 1314eaf38c9bSShihong Wang } 1315eaf38c9bSShihong Wang 13164a9bb682SChaoyong He net_hw->ipsec_data->sa_free_cnt++; 13174a9bb682SChaoyong He net_hw->ipsec_data->sa_entries[sa_index] = NULL; 1318eaf38c9bSShihong Wang 1319eaf38c9bSShihong Wang return 0; 1320eaf38c9bSShihong Wang } 1321eaf38c9bSShihong Wang 1322eaf38c9bSShihong Wang static int 1323eaf38c9bSShihong Wang nfp_crypto_remove_session(void *device, 1324eaf38c9bSShihong Wang struct rte_security_session *session) 1325eaf38c9bSShihong Wang { 1326eaf38c9bSShihong Wang int ret; 1327eaf38c9bSShihong Wang struct rte_eth_dev *eth_dev; 1328eaf38c9bSShihong Wang struct nfp_ipsec_session *priv_session; 1329eaf38c9bSShihong Wang 1330eaf38c9bSShihong Wang eth_dev = device; 1331eaf38c9bSShihong Wang priv_session = SECURITY_GET_SESS_PRIV(session); 1332eaf38c9bSShihong Wang if (eth_dev != priv_session->dev) { 1333*b6de4353SZerun Fu PMD_DRV_LOG(ERR, "Session not bound to this device."); 1334eaf38c9bSShihong Wang return -ENODEV; 1335eaf38c9bSShihong Wang } 1336eaf38c9bSShihong Wang 1337eaf38c9bSShihong Wang ret = nfp_crypto_remove_sa(eth_dev, priv_session); 1338eaf38c9bSShihong Wang if (ret < 0) { 1339*b6de4353SZerun Fu PMD_DRV_LOG(ERR, "Failed to remove session."); 1340eaf38c9bSShihong Wang return -EFAULT; 1341eaf38c9bSShihong Wang } 1342eaf38c9bSShihong Wang 1343eaf38c9bSShihong Wang memset(priv_session, 0, sizeof(struct nfp_ipsec_session)); 1344eaf38c9bSShihong Wang 1345eaf38c9bSShihong Wang return 0; 1346eaf38c9bSShihong Wang } 1347eaf38c9bSShihong Wang 1348e6d69ea0SShihong Wang static const struct rte_security_ops nfp_security_ops = { 13493d21da66SChang Miao .session_create = nfp_crypto_create_session, 13507e6c8063SShihong Wang .session_update = nfp_crypto_update_session, 1351e6d69ea0SShihong Wang .session_get_size = nfp_security_session_get_size, 13527fb333e9SShihong Wang .session_stats_get = nfp_security_session_get_stats, 1353eaf38c9bSShihong Wang .session_destroy = nfp_crypto_remove_session, 1354310a1780SShihong Wang .set_pkt_metadata = nfp_security_set_pkt_metadata, 1355e6d69ea0SShihong Wang .capabilities_get = nfp_crypto_capabilities_get, 1356e6d69ea0SShihong Wang }; 135754713740SChang Miao 135854713740SChang Miao static int 135954713740SChang Miao nfp_ipsec_ctx_create(struct rte_eth_dev *dev, 136054713740SChang Miao struct nfp_net_ipsec_data *data) 136154713740SChang Miao { 136254713740SChang Miao struct rte_security_ctx *ctx; 136354713740SChang Miao static const struct rte_mbuf_dynfield pkt_md_dynfield = { 136454713740SChang Miao .name = "nfp_ipsec_crypto_pkt_metadata", 136554713740SChang Miao .size = sizeof(struct nfp_tx_ipsec_desc_msg), 136608966fe7STyler Retzlaff .align = alignof(struct nfp_tx_ipsec_desc_msg), 136754713740SChang Miao }; 136854713740SChang Miao 136954713740SChang Miao ctx = rte_zmalloc("security_ctx", 137054713740SChang Miao sizeof(struct rte_security_ctx), 0); 137154713740SChang Miao if (ctx == NULL) { 1372*b6de4353SZerun Fu PMD_INIT_LOG(ERR, "Failed to malloc security_ctx."); 137354713740SChang Miao return -ENOMEM; 137454713740SChang Miao } 137554713740SChang Miao 137654713740SChang Miao ctx->device = dev; 137754713740SChang Miao ctx->ops = &nfp_security_ops; 137854713740SChang Miao ctx->sess_cnt = 0; 137954713740SChang Miao dev->security_ctx = ctx; 138054713740SChang Miao 138154713740SChang Miao data->pkt_dynfield_offset = rte_mbuf_dynfield_register(&pkt_md_dynfield); 138254713740SChang Miao if (data->pkt_dynfield_offset < 0) { 1383*b6de4353SZerun Fu PMD_INIT_LOG(ERR, "Failed to register mbuf esn_dynfield."); 138454713740SChang Miao return -ENOMEM; 138554713740SChang Miao } 138654713740SChang Miao 138754713740SChang Miao return 0; 138854713740SChang Miao } 138954713740SChang Miao 139054713740SChang Miao int 139154713740SChang Miao nfp_ipsec_init(struct rte_eth_dev *dev) 139254713740SChang Miao { 139354713740SChang Miao int ret; 139454713740SChang Miao uint32_t cap_extend; 13954a9bb682SChaoyong He struct nfp_net_hw *net_hw; 139654713740SChang Miao struct nfp_net_ipsec_data *data; 139754713740SChang Miao 13989d723baaSChaoyong He net_hw = dev->data->dev_private; 139954713740SChang Miao 14004a9bb682SChaoyong He cap_extend = net_hw->super.cap_ext; 140154713740SChang Miao if ((cap_extend & NFP_NET_CFG_CTRL_IPSEC) == 0) { 1402*b6de4353SZerun Fu PMD_INIT_LOG(INFO, "Unsupported IPsec extend capability."); 140354713740SChang Miao return 0; 140454713740SChang Miao } 140554713740SChang Miao 140654713740SChang Miao data = rte_zmalloc("ipsec_data", sizeof(struct nfp_net_ipsec_data), 0); 140754713740SChang Miao if (data == NULL) { 1408*b6de4353SZerun Fu PMD_INIT_LOG(ERR, "Failed to malloc ipsec_data."); 140954713740SChang Miao return -ENOMEM; 141054713740SChang Miao } 141154713740SChang Miao 141254713740SChang Miao data->pkt_dynfield_offset = -1; 141354713740SChang Miao data->sa_free_cnt = NFP_NET_IPSEC_MAX_SA_CNT; 14144a9bb682SChaoyong He net_hw->ipsec_data = data; 141554713740SChang Miao 141654713740SChang Miao ret = nfp_ipsec_ctx_create(dev, data); 141754713740SChang Miao if (ret != 0) { 1418*b6de4353SZerun Fu PMD_INIT_LOG(ERR, "Failed to create IPsec ctx."); 141954713740SChang Miao goto ipsec_cleanup; 142054713740SChang Miao } 142154713740SChang Miao 142254713740SChang Miao return 0; 142354713740SChang Miao 142454713740SChang Miao ipsec_cleanup: 142554713740SChang Miao nfp_ipsec_uninit(dev); 142654713740SChang Miao 142754713740SChang Miao return ret; 142854713740SChang Miao } 142954713740SChang Miao 143054713740SChang Miao static void 143154713740SChang Miao nfp_ipsec_ctx_destroy(struct rte_eth_dev *dev) 143254713740SChang Miao { 143354713740SChang Miao rte_free(dev->security_ctx); 143454713740SChang Miao } 143554713740SChang Miao 143654713740SChang Miao void 143754713740SChang Miao nfp_ipsec_uninit(struct rte_eth_dev *dev) 143854713740SChang Miao { 143954713740SChang Miao uint16_t i; 144054713740SChang Miao uint32_t cap_extend; 14414a9bb682SChaoyong He struct nfp_net_hw *net_hw; 144254713740SChang Miao struct nfp_ipsec_session *priv_session; 144354713740SChang Miao 14449d723baaSChaoyong He net_hw = dev->data->dev_private; 144554713740SChang Miao 14464a9bb682SChaoyong He cap_extend = net_hw->super.cap_ext; 144754713740SChang Miao if ((cap_extend & NFP_NET_CFG_CTRL_IPSEC) == 0) { 1448*b6de4353SZerun Fu PMD_INIT_LOG(INFO, "Unsupported IPsec extend capability."); 144954713740SChang Miao return; 145054713740SChang Miao } 145154713740SChang Miao 145254713740SChang Miao nfp_ipsec_ctx_destroy(dev); 145354713740SChang Miao 14544a9bb682SChaoyong He if (net_hw->ipsec_data == NULL) { 145554713740SChang Miao PMD_INIT_LOG(INFO, "IPsec data is NULL!"); 145654713740SChang Miao return; 145754713740SChang Miao } 145854713740SChang Miao 145954713740SChang Miao for (i = 0; i < NFP_NET_IPSEC_MAX_SA_CNT; i++) { 14604a9bb682SChaoyong He priv_session = net_hw->ipsec_data->sa_entries[i]; 146154713740SChang Miao if (priv_session != NULL) 146254713740SChang Miao memset(priv_session, 0, sizeof(struct nfp_ipsec_session)); 146354713740SChang Miao } 146454713740SChang Miao 14654a9bb682SChaoyong He rte_free(net_hw->ipsec_data); 146654713740SChang Miao } 146754713740SChang Miao 1468