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