1e23731dbSKonstantin Belousov /*- 2e23731dbSKonstantin Belousov * Copyright (c) 2023 NVIDIA corporation & affiliates. 3e23731dbSKonstantin Belousov * 4e23731dbSKonstantin Belousov * Redistribution and use in source and binary forms, with or without 5e23731dbSKonstantin Belousov * modification, are permitted provided that the following conditions 6e23731dbSKonstantin Belousov * are met: 7e23731dbSKonstantin Belousov * 1. Redistributions of source code must retain the above copyright 8e23731dbSKonstantin Belousov * notice, this list of conditions and the following disclaimer. 9e23731dbSKonstantin Belousov * 2. Redistributions in binary form must reproduce the above copyright 10e23731dbSKonstantin Belousov * notice, this list of conditions and the following disclaimer in the 11e23731dbSKonstantin Belousov * documentation and/or other materials provided with the distribution. 12e23731dbSKonstantin Belousov * 13e23731dbSKonstantin Belousov * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND 14e23731dbSKonstantin Belousov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15e23731dbSKonstantin Belousov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16e23731dbSKonstantin Belousov * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17e23731dbSKonstantin Belousov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18e23731dbSKonstantin Belousov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19e23731dbSKonstantin Belousov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20e23731dbSKonstantin Belousov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21e23731dbSKonstantin Belousov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22e23731dbSKonstantin Belousov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23e23731dbSKonstantin Belousov * SUCH DAMAGE. 24e23731dbSKonstantin Belousov * 25e23731dbSKonstantin Belousov */ 26e23731dbSKonstantin Belousov 27e23731dbSKonstantin Belousov #include "opt_ipsec.h" 28e23731dbSKonstantin Belousov 29e23731dbSKonstantin Belousov #include <sys/types.h> 30e23731dbSKonstantin Belousov #include <netinet/in.h> 31e23731dbSKonstantin Belousov #include <sys/socket.h> 32e23731dbSKonstantin Belousov #include <sys/param.h> 33e23731dbSKonstantin Belousov #include <sys/systm.h> 34e23731dbSKonstantin Belousov #include <net/if.h> 35e23731dbSKonstantin Belousov #include <net/if_var.h> 36e23731dbSKonstantin Belousov #include <net/pfkeyv2.h> 37e23731dbSKonstantin Belousov #include <netipsec/key_var.h> 38e23731dbSKonstantin Belousov #include <netipsec/keydb.h> 39e23731dbSKonstantin Belousov #include <netipsec/ipsec.h> 40e23731dbSKonstantin Belousov #include <netipsec/xform.h> 41e23731dbSKonstantin Belousov #include <netipsec/ipsec_offload.h> 42e23731dbSKonstantin Belousov #include <dev/mlx5/fs.h> 43e23731dbSKonstantin Belousov #include <dev/mlx5/mlx5_en/en.h> 44e23731dbSKonstantin Belousov #include <dev/mlx5/mlx5_accel/ipsec.h> 45e23731dbSKonstantin Belousov 46e23731dbSKonstantin Belousov #define MLX5_IPSEC_RESCHED msecs_to_jiffies(1000) 47e23731dbSKonstantin Belousov 48*828da10bSKonstantin Belousov static void mlx5e_if_sa_deinstall_onekey(struct ifnet *ifp, u_int dev_spi, 49*828da10bSKonstantin Belousov void *priv); 50e23731dbSKonstantin Belousov static int mlx5e_if_sa_deinstall(struct ifnet *ifp, u_int dev_spi, void *priv); 51e23731dbSKonstantin Belousov 52e23731dbSKonstantin Belousov static struct mlx5e_ipsec_sa_entry *to_ipsec_sa_entry(void *x) 53e23731dbSKonstantin Belousov { 54e23731dbSKonstantin Belousov return (struct mlx5e_ipsec_sa_entry *)x; 55e23731dbSKonstantin Belousov } 56e23731dbSKonstantin Belousov 57e23731dbSKonstantin Belousov static struct mlx5e_ipsec_pol_entry *to_ipsec_pol_entry(void *x) 58e23731dbSKonstantin Belousov { 59e23731dbSKonstantin Belousov return (struct mlx5e_ipsec_pol_entry *)x; 60e23731dbSKonstantin Belousov } 61e23731dbSKonstantin Belousov 62e23731dbSKonstantin Belousov static void 63e23731dbSKonstantin Belousov mlx5e_ipsec_handle_counters_onedir(struct mlx5e_ipsec_sa_entry *sa_entry, 64e23731dbSKonstantin Belousov u64 *packets, u64 *bytes) 65e23731dbSKonstantin Belousov { 66e23731dbSKonstantin Belousov struct mlx5e_ipsec_rule *ipsec_rule = &sa_entry->ipsec_rule; 67e23731dbSKonstantin Belousov struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry); 68e23731dbSKonstantin Belousov 69e23731dbSKonstantin Belousov mlx5_fc_query(mdev, ipsec_rule->fc, packets, bytes); 70e23731dbSKonstantin Belousov } 71e23731dbSKonstantin Belousov 72e23731dbSKonstantin Belousov static struct mlx5e_ipsec_sa_entry * 73e23731dbSKonstantin Belousov mlx5e_ipsec_other_sa_entry(struct mlx5e_ipsec_priv_bothdir *pb, 74e23731dbSKonstantin Belousov struct mlx5e_ipsec_sa_entry *sa_entry) 75e23731dbSKonstantin Belousov { 76e23731dbSKonstantin Belousov return (pb->priv_in == sa_entry ? pb->priv_out : pb->priv_in); 77e23731dbSKonstantin Belousov } 78e23731dbSKonstantin Belousov 79e23731dbSKonstantin Belousov static void 80e23731dbSKonstantin Belousov mlx5e_ipsec_handle_counters(struct work_struct *_work) 81e23731dbSKonstantin Belousov { 82e23731dbSKonstantin Belousov struct mlx5e_ipsec_dwork *dwork = 83e23731dbSKonstantin Belousov container_of(_work, struct mlx5e_ipsec_dwork, dwork.work); 84e23731dbSKonstantin Belousov struct mlx5e_ipsec_sa_entry *sa_entry = dwork->sa_entry; 85e23731dbSKonstantin Belousov struct mlx5e_ipsec_sa_entry *other_sa_entry; 86e23731dbSKonstantin Belousov u64 bytes, bytes1, packets1, packets; 87e23731dbSKonstantin Belousov 88e23731dbSKonstantin Belousov if (sa_entry->attrs.drop) 89e23731dbSKonstantin Belousov return; 90e23731dbSKonstantin Belousov other_sa_entry = mlx5e_ipsec_other_sa_entry(dwork->pb, sa_entry); 91e23731dbSKonstantin Belousov if (other_sa_entry == NULL || other_sa_entry->attrs.drop) 92e23731dbSKonstantin Belousov return; 93e23731dbSKonstantin Belousov 94e23731dbSKonstantin Belousov mlx5e_ipsec_handle_counters_onedir(sa_entry, &packets, &bytes); 95e23731dbSKonstantin Belousov mlx5e_ipsec_handle_counters_onedir(other_sa_entry, &packets1, &bytes1); 96e23731dbSKonstantin Belousov packets += packets1; 97e23731dbSKonstantin Belousov bytes += bytes1; 98e23731dbSKonstantin Belousov 99e23731dbSKonstantin Belousov #ifdef IPSEC_OFFLOAD 100e23731dbSKonstantin Belousov ipsec_accel_drv_sa_lifetime_update(sa_entry->savp, sa_entry->ifp, 101e23731dbSKonstantin Belousov sa_entry->kspi, bytes, packets); 102e23731dbSKonstantin Belousov #endif 103e23731dbSKonstantin Belousov 104e23731dbSKonstantin Belousov queue_delayed_work(sa_entry->ipsec->wq, &dwork->dwork, 105e23731dbSKonstantin Belousov MLX5_IPSEC_RESCHED); 106e23731dbSKonstantin Belousov } 107e23731dbSKonstantin Belousov 108e23731dbSKonstantin Belousov static int 109e23731dbSKonstantin Belousov mlx5e_ipsec_create_dwork(struct mlx5e_ipsec_sa_entry *sa_entry, 110e23731dbSKonstantin Belousov struct mlx5e_ipsec_priv_bothdir *pb) 111e23731dbSKonstantin Belousov { 112e23731dbSKonstantin Belousov struct mlx5e_ipsec_dwork *dwork; 113e23731dbSKonstantin Belousov 114e23731dbSKonstantin Belousov dwork = kzalloc(sizeof(*dwork), GFP_KERNEL); 115e23731dbSKonstantin Belousov if (!dwork) 116e23731dbSKonstantin Belousov return (ENOMEM); 117e23731dbSKonstantin Belousov 118e23731dbSKonstantin Belousov dwork->sa_entry = sa_entry; 119e23731dbSKonstantin Belousov dwork->pb = pb; 120e23731dbSKonstantin Belousov INIT_DELAYED_WORK(&dwork->dwork, mlx5e_ipsec_handle_counters); 121e23731dbSKonstantin Belousov sa_entry->dwork = dwork; 122e23731dbSKonstantin Belousov return 0; 123e23731dbSKonstantin Belousov } 124e23731dbSKonstantin Belousov 125e23731dbSKonstantin Belousov static int mlx5_xform_ah_authsize(const struct auth_hash *esph) 126e23731dbSKonstantin Belousov { 127e23731dbSKonstantin Belousov int alen; 128e23731dbSKonstantin Belousov 129e23731dbSKonstantin Belousov if (esph == NULL) 130e23731dbSKonstantin Belousov return 0; 131e23731dbSKonstantin Belousov 132e23731dbSKonstantin Belousov switch (esph->type) { 133e23731dbSKonstantin Belousov case CRYPTO_SHA2_256_HMAC: 134e23731dbSKonstantin Belousov case CRYPTO_SHA2_384_HMAC: 135e23731dbSKonstantin Belousov case CRYPTO_SHA2_512_HMAC: 136e23731dbSKonstantin Belousov alen = esph->hashsize / 2; /* RFC4868 2.3 */ 137e23731dbSKonstantin Belousov break; 138e23731dbSKonstantin Belousov 139e23731dbSKonstantin Belousov case CRYPTO_POLY1305: 140e23731dbSKonstantin Belousov case CRYPTO_AES_NIST_GMAC: 141e23731dbSKonstantin Belousov alen = esph->hashsize; 142e23731dbSKonstantin Belousov break; 143e23731dbSKonstantin Belousov 144e23731dbSKonstantin Belousov default: 145e23731dbSKonstantin Belousov alen = AH_HMAC_HASHLEN; 146e23731dbSKonstantin Belousov break; 147e23731dbSKonstantin Belousov } 148e23731dbSKonstantin Belousov 149e23731dbSKonstantin Belousov return alen; 150e23731dbSKonstantin Belousov } 151e23731dbSKonstantin Belousov 152e23731dbSKonstantin Belousov void mlx5e_ipsec_build_accel_xfrm_attrs(struct mlx5e_ipsec_sa_entry *sa_entry, 153e23731dbSKonstantin Belousov struct mlx5_accel_esp_xfrm_attrs *attrs, 154e23731dbSKonstantin Belousov u8 dir) 155e23731dbSKonstantin Belousov { 156e23731dbSKonstantin Belousov struct secasvar *savp = sa_entry->savp; 157e23731dbSKonstantin Belousov const struct auth_hash *esph = savp->tdb_authalgxform; 158e23731dbSKonstantin Belousov struct aes_gcm_keymat *aes_gcm = &attrs->aes_gcm; 159e23731dbSKonstantin Belousov struct secasindex *saidx = &savp->sah->saidx; 160e23731dbSKonstantin Belousov struct seckey *key_encap = savp->key_enc; 161e23731dbSKonstantin Belousov int key_len; 162e23731dbSKonstantin Belousov 163e23731dbSKonstantin Belousov memset(attrs, 0, sizeof(*attrs)); 164e23731dbSKonstantin Belousov 165e23731dbSKonstantin Belousov /* subtract off the salt, RFC4106, 8.1 and RFC3686, 5.1 */ 166e23731dbSKonstantin Belousov key_len = _KEYLEN(key_encap) - SAV_ISCTRORGCM(savp) * 4 - SAV_ISCHACHA(savp) * 4; 167e23731dbSKonstantin Belousov 168e23731dbSKonstantin Belousov memcpy(aes_gcm->aes_key, key_encap->key_data, key_len); 169e23731dbSKonstantin Belousov aes_gcm->key_len = key_len; 170e23731dbSKonstantin Belousov 171e23731dbSKonstantin Belousov /* salt and seq_iv */ 172e23731dbSKonstantin Belousov aes_gcm->seq_iv = 0; 173e23731dbSKonstantin Belousov memcpy(&aes_gcm->salt, key_encap->key_data + key_len, 174e23731dbSKonstantin Belousov sizeof(aes_gcm->salt)); 175e23731dbSKonstantin Belousov 176e23731dbSKonstantin Belousov switch (savp->alg_enc) { 177e23731dbSKonstantin Belousov case SADB_X_EALG_AESGCM8: 178e23731dbSKonstantin Belousov attrs->authsize = 8 / 4; /* in dwords */ 179e23731dbSKonstantin Belousov break; 180e23731dbSKonstantin Belousov case SADB_X_EALG_AESGCM12: 181e23731dbSKonstantin Belousov attrs->authsize = 12 / 4; /* in dwords */ 182e23731dbSKonstantin Belousov break; 183e23731dbSKonstantin Belousov case SADB_X_EALG_AESGCM16: 184e23731dbSKonstantin Belousov attrs->authsize = 16 / 4; /* in dwords */ 185e23731dbSKonstantin Belousov break; 186e23731dbSKonstantin Belousov default: break; 187e23731dbSKonstantin Belousov } 188e23731dbSKonstantin Belousov 189e23731dbSKonstantin Belousov /* iv len */ 190e23731dbSKonstantin Belousov aes_gcm->icv_len = mlx5_xform_ah_authsize(esph); //TBD: check if value make sense 191e23731dbSKonstantin Belousov 192e23731dbSKonstantin Belousov attrs->dir = dir; 193e23731dbSKonstantin Belousov /* spi - host order */ 194e23731dbSKonstantin Belousov attrs->spi = ntohl(savp->spi); 195e23731dbSKonstantin Belousov attrs->family = saidx->dst.sa.sa_family; 196e23731dbSKonstantin Belousov attrs->reqid = saidx->reqid; 197e23731dbSKonstantin Belousov 198e23731dbSKonstantin Belousov if (saidx->src.sa.sa_family == AF_INET) { 199e23731dbSKonstantin Belousov attrs->saddr.a4 = saidx->src.sin.sin_addr.s_addr; 200e23731dbSKonstantin Belousov attrs->daddr.a4 = saidx->dst.sin.sin_addr.s_addr; 201e23731dbSKonstantin Belousov } else { 202e23731dbSKonstantin Belousov memcpy(&attrs->saddr.a6, &saidx->src.sin6.sin6_addr, 16); 203e23731dbSKonstantin Belousov memcpy(&attrs->daddr.a6, &saidx->dst.sin6.sin6_addr, 16); 204e23731dbSKonstantin Belousov } 205e23731dbSKonstantin Belousov 206e23731dbSKonstantin Belousov if (savp->natt) { 207e23731dbSKonstantin Belousov attrs->encap = true; 208e23731dbSKonstantin Belousov attrs->sport = savp->natt->sport; 209e23731dbSKonstantin Belousov attrs->dport = savp->natt->dport; 210e23731dbSKonstantin Belousov } 211e23731dbSKonstantin Belousov 212e23731dbSKonstantin Belousov if (savp->flags & SADB_X_SAFLAGS_ESN) { 213e23731dbSKonstantin Belousov /* We support replay window with ESN only */ 214e23731dbSKonstantin Belousov attrs->replay_esn.trigger = true; 215e23731dbSKonstantin Belousov if (sa_entry->esn_state.esn_msb) 216e23731dbSKonstantin Belousov attrs->replay_esn.esn = sa_entry->esn_state.esn; 217e23731dbSKonstantin Belousov else 218e23731dbSKonstantin Belousov /* According to RFC4303, section "3.3.3. Sequence Number Generation", 219e23731dbSKonstantin Belousov * the first packet sent using a given SA will contain a sequence 220e23731dbSKonstantin Belousov * number of 1. 221e23731dbSKonstantin Belousov */ 222e23731dbSKonstantin Belousov attrs->replay_esn.esn = max_t(u32, sa_entry->esn_state.esn, 1); 223e23731dbSKonstantin Belousov attrs->replay_esn.esn_msb = sa_entry->esn_state.esn_msb; 224e23731dbSKonstantin Belousov attrs->replay_esn.overlap = sa_entry->esn_state.overlap; 225e23731dbSKonstantin Belousov 226e23731dbSKonstantin Belousov if (savp->replay) { 227e23731dbSKonstantin Belousov switch (savp->replay->wsize) { 228e23731dbSKonstantin Belousov case 4: 229e23731dbSKonstantin Belousov attrs->replay_esn.replay_window = MLX5_IPSEC_ASO_REPLAY_WIN_32BIT; 230e23731dbSKonstantin Belousov break; 231e23731dbSKonstantin Belousov case 8: 232e23731dbSKonstantin Belousov attrs->replay_esn.replay_window = MLX5_IPSEC_ASO_REPLAY_WIN_64BIT; 233e23731dbSKonstantin Belousov break; 234e23731dbSKonstantin Belousov case 16: 235e23731dbSKonstantin Belousov attrs->replay_esn.replay_window = MLX5_IPSEC_ASO_REPLAY_WIN_128BIT; 236e23731dbSKonstantin Belousov break; 237e23731dbSKonstantin Belousov case 32: 238e23731dbSKonstantin Belousov attrs->replay_esn.replay_window = MLX5_IPSEC_ASO_REPLAY_WIN_256BIT; 239e23731dbSKonstantin Belousov break; 240e23731dbSKonstantin Belousov default: 241e23731dbSKonstantin Belousov /* Do nothing */ 242e23731dbSKonstantin Belousov break; 243e23731dbSKonstantin Belousov } 244e23731dbSKonstantin Belousov } 245e23731dbSKonstantin Belousov } 246e23731dbSKonstantin Belousov } 247e23731dbSKonstantin Belousov 248e23731dbSKonstantin Belousov static int mlx5e_xfrm_validate_state(struct mlx5_core_dev *mdev, 249e23731dbSKonstantin Belousov struct secasvar *savp) 250e23731dbSKonstantin Belousov { 251e23731dbSKonstantin Belousov struct secasindex *saidx = &savp->sah->saidx; 252e23731dbSKonstantin Belousov struct seckey *key_encp = savp->key_enc; 253e23731dbSKonstantin Belousov int keylen; 254e23731dbSKonstantin Belousov 255e23731dbSKonstantin Belousov if (!(mlx5_ipsec_device_caps(mdev) & 256e23731dbSKonstantin Belousov MLX5_IPSEC_CAP_PACKET_OFFLOAD)) { 257e23731dbSKonstantin Belousov mlx5_core_err(mdev, "FULL offload is not supported\n"); 258e23731dbSKonstantin Belousov return (EINVAL); 259e23731dbSKonstantin Belousov } 260e23731dbSKonstantin Belousov if (savp->alg_enc == SADB_EALG_NONE) { 261e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Cannot offload authenticated xfrm states\n"); 262e23731dbSKonstantin Belousov return (EINVAL); 263e23731dbSKonstantin Belousov } 264e23731dbSKonstantin Belousov if (savp->alg_enc != SADB_X_EALG_AESGCM16) { 265e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Only IPSec aes-gcm-16 encryption protocol may be offloaded\n"); 266e23731dbSKonstantin Belousov return (EINVAL); 267e23731dbSKonstantin Belousov } 268e23731dbSKonstantin Belousov if (savp->tdb_compalgxform) { 269e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Cannot offload compressed xfrm states\n"); 270e23731dbSKonstantin Belousov return (EINVAL); 271e23731dbSKonstantin Belousov } 272e23731dbSKonstantin Belousov if (savp->alg_auth != SADB_X_AALG_AES128GMAC && savp->alg_auth != SADB_X_AALG_AES256GMAC) { 273e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Cannot offload xfrm states with AEAD key length other than 128/256 bits\n"); 274e23731dbSKonstantin Belousov return (EINVAL); 275e23731dbSKonstantin Belousov } 276e23731dbSKonstantin Belousov if ((saidx->dst.sa.sa_family != AF_INET && saidx->dst.sa.sa_family != AF_INET6) || 277e23731dbSKonstantin Belousov (saidx->src.sa.sa_family != AF_INET && saidx->src.sa.sa_family != AF_INET6)) { 278e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Only IPv4/6 xfrm states may be offloaded\n"); 279e23731dbSKonstantin Belousov return (EINVAL); 280e23731dbSKonstantin Belousov } 281e23731dbSKonstantin Belousov if (saidx->proto != IPPROTO_ESP) { 282e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Only ESP xfrm state may be offloaded\n"); 283e23731dbSKonstantin Belousov return (EINVAL); 284e23731dbSKonstantin Belousov } 285e23731dbSKonstantin Belousov /* subtract off the salt, RFC4106, 8.1 and RFC3686, 5.1 */ 286e23731dbSKonstantin Belousov keylen = _KEYLEN(key_encp) - SAV_ISCTRORGCM(savp) * 4 - SAV_ISCHACHA(savp) * 4; 287e23731dbSKonstantin Belousov if (keylen != 128/8 && keylen != 256 / 8) { 288e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Cannot offload xfrm states with AEAD key length other than 128/256 bit\n"); 289e23731dbSKonstantin Belousov return (EINVAL); 290e23731dbSKonstantin Belousov } 291e23731dbSKonstantin Belousov 292e23731dbSKonstantin Belousov if (saidx->mode != IPSEC_MODE_TRANSPORT) { 293e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Only transport xfrm states may be offloaded in full offlaod mode\n"); 294e23731dbSKonstantin Belousov return (EINVAL); 295e23731dbSKonstantin Belousov } 296e23731dbSKonstantin Belousov 297e23731dbSKonstantin Belousov if (savp->natt) { 298e23731dbSKonstantin Belousov if (!(mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_ESPINUDP)) { 299e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Encapsulation is not supported\n"); 300e23731dbSKonstantin Belousov return (EINVAL); 301e23731dbSKonstantin Belousov } 302e23731dbSKonstantin Belousov } 303e23731dbSKonstantin Belousov 304e23731dbSKonstantin Belousov if (savp->replay && savp->replay->wsize != 0 && savp->replay->wsize != 4 && 305e23731dbSKonstantin Belousov savp->replay->wsize != 8 && savp->replay->wsize != 16 && savp->replay->wsize != 32) { 306e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Unsupported replay window size %d\n", savp->replay->wsize); 307e23731dbSKonstantin Belousov return (EINVAL); 308e23731dbSKonstantin Belousov } 309e23731dbSKonstantin Belousov 310e23731dbSKonstantin Belousov if ((savp->flags & SADB_X_SAFLAGS_ESN) != 0) { 311e23731dbSKonstantin Belousov if ((mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_ESN) == 0) { 312e23731dbSKonstantin Belousov mlx5_core_err(mdev, "ESN is not supported\n"); 313e23731dbSKonstantin Belousov return (EINVAL); 314e23731dbSKonstantin Belousov } 315e23731dbSKonstantin Belousov } else if (savp->replay != NULL && savp->replay->wsize != 0) { 316e23731dbSKonstantin Belousov mlx5_core_warn(mdev, 317e23731dbSKonstantin Belousov "non-ESN but replay-protect SA offload is not supported\n"); 318e23731dbSKonstantin Belousov return (EINVAL); 319e23731dbSKonstantin Belousov } 320e23731dbSKonstantin Belousov return 0; 321e23731dbSKonstantin Belousov } 322e23731dbSKonstantin Belousov 323e23731dbSKonstantin Belousov static int 324e23731dbSKonstantin Belousov mlx5e_if_sa_newkey_onedir(struct ifnet *ifp, void *sav, int dir, 325e23731dbSKonstantin Belousov u_int drv_spi, struct mlx5e_ipsec_sa_entry **privp, 326e23731dbSKonstantin Belousov struct mlx5e_ipsec_priv_bothdir *pb) 327e23731dbSKonstantin Belousov { 328e23731dbSKonstantin Belousov struct mlx5e_ipsec_sa_entry *sa_entry = NULL; 329e23731dbSKonstantin Belousov struct mlx5e_priv *priv = if_getsoftc(ifp); 330e23731dbSKonstantin Belousov struct mlx5_core_dev *mdev = priv->mdev; 331e23731dbSKonstantin Belousov struct mlx5e_ipsec *ipsec = priv->ipsec; 332e23731dbSKonstantin Belousov int err; 333e23731dbSKonstantin Belousov 334e23731dbSKonstantin Belousov if (priv->gone != 0 || ipsec == NULL) 335e23731dbSKonstantin Belousov return (EOPNOTSUPP); 336e23731dbSKonstantin Belousov 337e23731dbSKonstantin Belousov err = mlx5e_xfrm_validate_state(mdev, sav); 338e23731dbSKonstantin Belousov if (err) 339e23731dbSKonstantin Belousov return err; 340e23731dbSKonstantin Belousov 341e23731dbSKonstantin Belousov sa_entry = kzalloc(sizeof(*sa_entry), GFP_KERNEL); 342e23731dbSKonstantin Belousov if (sa_entry == NULL) 343e23731dbSKonstantin Belousov return (ENOMEM); 344e23731dbSKonstantin Belousov 345e23731dbSKonstantin Belousov sa_entry->kspi = drv_spi; 346e23731dbSKonstantin Belousov sa_entry->savp = sav; 347e23731dbSKonstantin Belousov sa_entry->ifp = ifp; 348e23731dbSKonstantin Belousov sa_entry->ipsec = ipsec; 349e23731dbSKonstantin Belousov 350e23731dbSKonstantin Belousov mlx5e_ipsec_build_accel_xfrm_attrs(sa_entry, &sa_entry->attrs, dir); 351e23731dbSKonstantin Belousov 352e23731dbSKonstantin Belousov err = mlx5e_ipsec_create_dwork(sa_entry, pb); 353e23731dbSKonstantin Belousov if (err) 354e23731dbSKonstantin Belousov goto err_xfrm; 355e23731dbSKonstantin Belousov 356e23731dbSKonstantin Belousov /* create hw context */ 357e23731dbSKonstantin Belousov err = mlx5_ipsec_create_sa_ctx(sa_entry); 358e23731dbSKonstantin Belousov if (err) 359e23731dbSKonstantin Belousov goto err_sa_ctx; 360e23731dbSKonstantin Belousov 361e23731dbSKonstantin Belousov err = mlx5e_accel_ipsec_fs_add_rule(sa_entry); 362e23731dbSKonstantin Belousov if (err) 363e23731dbSKonstantin Belousov goto err_fs; 364e23731dbSKonstantin Belousov 365e23731dbSKonstantin Belousov *privp = sa_entry; 366e23731dbSKonstantin Belousov if (sa_entry->dwork) 367e23731dbSKonstantin Belousov queue_delayed_work(ipsec->wq, &sa_entry->dwork->dwork, MLX5_IPSEC_RESCHED); 368e23731dbSKonstantin Belousov 369e23731dbSKonstantin Belousov err = xa_insert(&mdev->ipsec_sadb, sa_entry->ipsec_obj_id, sa_entry, GFP_KERNEL); 370e23731dbSKonstantin Belousov if (err) 371e23731dbSKonstantin Belousov goto err_xa; 372e23731dbSKonstantin Belousov 373e23731dbSKonstantin Belousov return 0; 374e23731dbSKonstantin Belousov 375e23731dbSKonstantin Belousov err_xa: 376e23731dbSKonstantin Belousov if (sa_entry->dwork) 377e23731dbSKonstantin Belousov cancel_delayed_work_sync(&sa_entry->dwork->dwork); 378e23731dbSKonstantin Belousov mlx5e_accel_ipsec_fs_del_rule(sa_entry); 379e23731dbSKonstantin Belousov err_fs: 380e23731dbSKonstantin Belousov mlx5_ipsec_free_sa_ctx(sa_entry); 381e23731dbSKonstantin Belousov err_sa_ctx: 382e23731dbSKonstantin Belousov kfree(sa_entry->dwork); 383*828da10bSKonstantin Belousov sa_entry->dwork = NULL; 384e23731dbSKonstantin Belousov err_xfrm: 385e23731dbSKonstantin Belousov kfree(sa_entry); 386e23731dbSKonstantin Belousov mlx5_en_err(ifp, "Device failed to offload this state"); 387e23731dbSKonstantin Belousov return err; 388e23731dbSKonstantin Belousov } 389e23731dbSKonstantin Belousov 390e23731dbSKonstantin Belousov static int 391e23731dbSKonstantin Belousov mlx5e_if_sa_newkey(struct ifnet *ifp, void *sav, u_int dev_spi, void **privp) 392e23731dbSKonstantin Belousov { 393e23731dbSKonstantin Belousov struct mlx5e_ipsec_priv_bothdir *pb; 394e23731dbSKonstantin Belousov int error; 395e23731dbSKonstantin Belousov 396e23731dbSKonstantin Belousov pb = malloc(sizeof(struct mlx5e_ipsec_priv_bothdir), M_DEVBUF, 397e23731dbSKonstantin Belousov M_WAITOK | M_ZERO); 398e23731dbSKonstantin Belousov error = mlx5e_if_sa_newkey_onedir(ifp, sav, IPSEC_DIR_INBOUND, 399e23731dbSKonstantin Belousov dev_spi, &pb->priv_in, pb); 400e23731dbSKonstantin Belousov if (error != 0) { 401e23731dbSKonstantin Belousov free(pb, M_DEVBUF); 402e23731dbSKonstantin Belousov return (error); 403e23731dbSKonstantin Belousov } 404e23731dbSKonstantin Belousov error = mlx5e_if_sa_newkey_onedir(ifp, sav, IPSEC_DIR_OUTBOUND, 405e23731dbSKonstantin Belousov dev_spi, &pb->priv_out, pb); 406e23731dbSKonstantin Belousov if (error == 0) { 407e23731dbSKonstantin Belousov *privp = pb; 408e23731dbSKonstantin Belousov } else { 409*828da10bSKonstantin Belousov if (pb->priv_in->dwork != NULL) 410*828da10bSKonstantin Belousov cancel_delayed_work_sync(&pb->priv_in->dwork->dwork); 411*828da10bSKonstantin Belousov mlx5e_if_sa_deinstall_onekey(ifp, dev_spi, pb->priv_in); 412e23731dbSKonstantin Belousov free(pb, M_DEVBUF); 413e23731dbSKonstantin Belousov } 414e23731dbSKonstantin Belousov return (error); 415e23731dbSKonstantin Belousov } 416e23731dbSKonstantin Belousov 417e23731dbSKonstantin Belousov static void 418e23731dbSKonstantin Belousov mlx5e_if_sa_deinstall_onekey(struct ifnet *ifp, u_int dev_spi, void *priv) 419e23731dbSKonstantin Belousov { 420e23731dbSKonstantin Belousov struct mlx5e_ipsec_sa_entry *sa_entry = to_ipsec_sa_entry(priv); 421e23731dbSKonstantin Belousov struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry); 422e23731dbSKonstantin Belousov struct mlx5e_ipsec_sa_entry *old; 423e23731dbSKonstantin Belousov 424e23731dbSKonstantin Belousov old = xa_erase(&mdev->ipsec_sadb, sa_entry->ipsec_obj_id); 425e23731dbSKonstantin Belousov WARN_ON(old != sa_entry); 426e23731dbSKonstantin Belousov 427e23731dbSKonstantin Belousov mlx5e_accel_ipsec_fs_del_rule(sa_entry); 428e23731dbSKonstantin Belousov mlx5_ipsec_free_sa_ctx(sa_entry); 429e23731dbSKonstantin Belousov kfree(sa_entry->dwork); 430e23731dbSKonstantin Belousov kfree(sa_entry); 431e23731dbSKonstantin Belousov } 432e23731dbSKonstantin Belousov 433e23731dbSKonstantin Belousov static int 434e23731dbSKonstantin Belousov mlx5e_if_sa_deinstall(struct ifnet *ifp, u_int dev_spi, void *priv) 435e23731dbSKonstantin Belousov { 436e23731dbSKonstantin Belousov struct mlx5e_ipsec_priv_bothdir pb, *pbp; 437e23731dbSKonstantin Belousov 438e23731dbSKonstantin Belousov pbp = priv; 439e23731dbSKonstantin Belousov pb = *(struct mlx5e_ipsec_priv_bothdir *)priv; 440e23731dbSKonstantin Belousov pbp->priv_in = pbp->priv_out = NULL; 441e23731dbSKonstantin Belousov 442e23731dbSKonstantin Belousov if (pb.priv_in->dwork != NULL) 443e23731dbSKonstantin Belousov cancel_delayed_work_sync(&pb.priv_in->dwork->dwork); 444e23731dbSKonstantin Belousov if (pb.priv_out->dwork != NULL) 445e23731dbSKonstantin Belousov cancel_delayed_work_sync(&pb.priv_out->dwork->dwork); 446e23731dbSKonstantin Belousov 447e23731dbSKonstantin Belousov mlx5e_if_sa_deinstall_onekey(ifp, dev_spi, pb.priv_in); 448e23731dbSKonstantin Belousov mlx5e_if_sa_deinstall_onekey(ifp, dev_spi, pb.priv_out); 449e23731dbSKonstantin Belousov free(pbp, M_DEVBUF); 450e23731dbSKonstantin Belousov return (0); 451e23731dbSKonstantin Belousov } 452e23731dbSKonstantin Belousov 453e23731dbSKonstantin Belousov static void 454e23731dbSKonstantin Belousov mlx5e_if_sa_cnt_one(struct ifnet *ifp, void *sa, uint32_t drv_spi, 455e23731dbSKonstantin Belousov void *priv, u64 *bytes, u64 *packets) 456e23731dbSKonstantin Belousov { 457e23731dbSKonstantin Belousov struct mlx5e_ipsec_sa_entry *sa_entry = to_ipsec_sa_entry(priv); 458e23731dbSKonstantin Belousov struct mlx5e_ipsec_rule *ipsec_rule = &sa_entry->ipsec_rule; 459e23731dbSKonstantin Belousov struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry); 460e23731dbSKonstantin Belousov 461e23731dbSKonstantin Belousov mlx5_fc_query(mdev, ipsec_rule->fc, packets, bytes); 462e23731dbSKonstantin Belousov } 463e23731dbSKonstantin Belousov 464e23731dbSKonstantin Belousov static int 465e23731dbSKonstantin Belousov mlx5e_if_sa_cnt(struct ifnet *ifp, void *sa, uint32_t drv_spi, 466e23731dbSKonstantin Belousov void *priv, struct seclifetime *lt) 467e23731dbSKonstantin Belousov { 468e23731dbSKonstantin Belousov struct mlx5e_ipsec_priv_bothdir *pb; 469e23731dbSKonstantin Belousov u64 packets_in, packets_out; 470e23731dbSKonstantin Belousov u64 bytes_in, bytes_out; 471e23731dbSKonstantin Belousov 472e23731dbSKonstantin Belousov pb = priv; 473e23731dbSKonstantin Belousov mlx5e_if_sa_cnt_one(ifp, sa, drv_spi, pb->priv_in, 474e23731dbSKonstantin Belousov &bytes_in, &packets_in); 475e23731dbSKonstantin Belousov mlx5e_if_sa_cnt_one(ifp, sa, drv_spi, pb->priv_out, 476e23731dbSKonstantin Belousov &bytes_out, &packets_out); 477e23731dbSKonstantin Belousov /* TODO: remove this casting once Kostia changes allocation type to be u64 */ 478e23731dbSKonstantin Belousov lt->bytes = bytes_in + bytes_out; 479e23731dbSKonstantin Belousov lt->allocations = (uint32_t)(packets_in + packets_out); 480e23731dbSKonstantin Belousov return (0); 481e23731dbSKonstantin Belousov } 482e23731dbSKonstantin Belousov 483e23731dbSKonstantin Belousov static int mlx5e_xfrm_validate_policy(struct mlx5_core_dev *mdev, 484e23731dbSKonstantin Belousov struct secpolicy *sp, struct inpcb *inp) 485e23731dbSKonstantin Belousov { 486e23731dbSKonstantin Belousov struct secpolicyindex *spidx = &sp->spidx; 487e23731dbSKonstantin Belousov 488e23731dbSKonstantin Belousov if (!(mlx5_ipsec_device_caps(mdev) & 489e23731dbSKonstantin Belousov MLX5_IPSEC_CAP_PACKET_OFFLOAD)) { 490e23731dbSKonstantin Belousov mlx5_core_err(mdev, "FULL offload is not supported\n"); 491e23731dbSKonstantin Belousov return (EINVAL); 492e23731dbSKonstantin Belousov } 493e23731dbSKonstantin Belousov 494e23731dbSKonstantin Belousov if (sp->tcount > 1) { 495e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Can offload exactly one template, " 496e23731dbSKonstantin Belousov "not %d\n", sp->tcount); 497e23731dbSKonstantin Belousov return (EINVAL); 498e23731dbSKonstantin Belousov } 499e23731dbSKonstantin Belousov 500e23731dbSKonstantin Belousov if (sp->policy == IPSEC_POLICY_BYPASS && 501e23731dbSKonstantin Belousov !(mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_PRIO)) { 502e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Device does not support policy priority\n"); 503e23731dbSKonstantin Belousov return (EINVAL); 504e23731dbSKonstantin Belousov } 505e23731dbSKonstantin Belousov 506e23731dbSKonstantin Belousov if (sp->tcount > 0 && inp != NULL) { 507e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Not valid input data\n"); 508e23731dbSKonstantin Belousov return (EINVAL); 509e23731dbSKonstantin Belousov } 510e23731dbSKonstantin Belousov 511e23731dbSKonstantin Belousov if (spidx->dir != IPSEC_DIR_INBOUND && spidx->dir != IPSEC_DIR_OUTBOUND) { 512e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Wrong policy direction\n"); 513e23731dbSKonstantin Belousov return (EINVAL); 514e23731dbSKonstantin Belousov } 515e23731dbSKonstantin Belousov 516e23731dbSKonstantin Belousov if (sp->tcount > 0 && sp->req[0]->saidx.mode != IPSEC_MODE_TRANSPORT) { 517e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Device supports transport mode only"); 518e23731dbSKonstantin Belousov return (EINVAL); 519e23731dbSKonstantin Belousov } 520e23731dbSKonstantin Belousov 521e23731dbSKonstantin Belousov if (sp->policy != IPSEC_POLICY_DISCARD && 522e23731dbSKonstantin Belousov sp->policy != IPSEC_POLICY_IPSEC && sp->policy != IPSEC_POLICY_BYPASS) { 523e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Offloaded policy must be specific on its action\n"); 524e23731dbSKonstantin Belousov return (EINVAL); 525e23731dbSKonstantin Belousov } 526e23731dbSKonstantin Belousov 527e23731dbSKonstantin Belousov if (sp->policy == IPSEC_POLICY_BYPASS && !inp) { 528e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Missing port information for IKE bypass\n"); 529e23731dbSKonstantin Belousov return (EINVAL); 530e23731dbSKonstantin Belousov } 531e23731dbSKonstantin Belousov 532e23731dbSKonstantin Belousov if (inp != NULL) { 533e23731dbSKonstantin Belousov INP_RLOCK(inp); 534e23731dbSKonstantin Belousov if (inp->inp_socket == NULL || inp->inp_socket->so_proto-> 535e23731dbSKonstantin Belousov pr_protocol != IPPROTO_UDP) { 536e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Unsupported IKE bypass protocol %d\n", 537e23731dbSKonstantin Belousov inp->inp_socket == NULL ? -1 : 538e23731dbSKonstantin Belousov inp->inp_socket->so_proto->pr_protocol); 539e23731dbSKonstantin Belousov INP_RUNLOCK(inp); 540e23731dbSKonstantin Belousov return (EINVAL); 541e23731dbSKonstantin Belousov } 542e23731dbSKonstantin Belousov INP_RUNLOCK(inp); 543e23731dbSKonstantin Belousov } 544e23731dbSKonstantin Belousov 545e23731dbSKonstantin Belousov /* TODO fill relevant bits */ 546e23731dbSKonstantin Belousov return 0; 547e23731dbSKonstantin Belousov } 548e23731dbSKonstantin Belousov 549e23731dbSKonstantin Belousov static void mlx5e_ipsec_build_accel_pol_attrs(struct mlx5e_ipsec_pol_entry *pol_entry, 550e23731dbSKonstantin Belousov struct mlx5_accel_pol_xfrm_attrs *attrs, 551e23731dbSKonstantin Belousov struct inpcb *inp) 552e23731dbSKonstantin Belousov { 553e23731dbSKonstantin Belousov struct secpolicy *sp = pol_entry->sp; 554e23731dbSKonstantin Belousov struct secpolicyindex *spidx = &sp->spidx; 555e23731dbSKonstantin Belousov 556e23731dbSKonstantin Belousov memset(attrs, 0, sizeof(*attrs)); 557e23731dbSKonstantin Belousov 558e23731dbSKonstantin Belousov if (!inp) { 559e23731dbSKonstantin Belousov if (spidx->src.sa.sa_family == AF_INET) { 560e23731dbSKonstantin Belousov attrs->saddr.a4 = spidx->src.sin.sin_addr.s_addr; 561e23731dbSKonstantin Belousov attrs->daddr.a4 = spidx->dst.sin.sin_addr.s_addr; 562e23731dbSKonstantin Belousov } else if (spidx->src.sa.sa_family == AF_INET6) { 563e23731dbSKonstantin Belousov memcpy(&attrs->saddr.a6, &spidx->src.sin6.sin6_addr, 16); 564e23731dbSKonstantin Belousov memcpy(&attrs->daddr.a6, &spidx->dst.sin6.sin6_addr, 16); 565e23731dbSKonstantin Belousov } else { 566e23731dbSKonstantin Belousov KASSERT(0, ("unsupported family %d", spidx->src.sa.sa_family)); 567e23731dbSKonstantin Belousov } 568e23731dbSKonstantin Belousov attrs->family = spidx->src.sa.sa_family; 569e23731dbSKonstantin Belousov attrs->prio = 0; 570e23731dbSKonstantin Belousov attrs->action = sp->policy; 571e23731dbSKonstantin Belousov attrs->reqid = sp->req[0]->saidx.reqid; 572e23731dbSKonstantin Belousov } else { 573e23731dbSKonstantin Belousov INP_RLOCK(inp); 574e23731dbSKonstantin Belousov if ((inp->inp_vflag & INP_IPV4) != 0) { 575e23731dbSKonstantin Belousov attrs->saddr.a4 = inp->inp_laddr.s_addr; 576e23731dbSKonstantin Belousov attrs->daddr.a4 = inp->inp_faddr.s_addr; 577e23731dbSKonstantin Belousov attrs->family = AF_INET; 578e23731dbSKonstantin Belousov } else if ((inp->inp_vflag & INP_IPV6) != 0) { 579e23731dbSKonstantin Belousov memcpy(&attrs->saddr.a6, &inp->in6p_laddr, 16); 580e23731dbSKonstantin Belousov memcpy(&attrs->daddr.a6, &inp->in6p_laddr, 16); 581e23731dbSKonstantin Belousov attrs->family = AF_INET6; 582e23731dbSKonstantin Belousov } else { 583e23731dbSKonstantin Belousov KASSERT(0, ("unsupported family %d", inp->inp_vflag)); 584e23731dbSKonstantin Belousov } 585e23731dbSKonstantin Belousov attrs->upspec.dport = inp->inp_fport; 586e23731dbSKonstantin Belousov attrs->upspec.sport = inp->inp_lport; 587e23731dbSKonstantin Belousov attrs->upspec.proto = inp->inp_ip_p; 588e23731dbSKonstantin Belousov INP_RUNLOCK(inp); 589e23731dbSKonstantin Belousov 590e23731dbSKonstantin Belousov /* Give highest priority for PCB policies */ 591e23731dbSKonstantin Belousov attrs->prio = 1; 592e23731dbSKonstantin Belousov attrs->action = IPSEC_POLICY_IPSEC; 593e23731dbSKonstantin Belousov } 594e23731dbSKonstantin Belousov attrs->dir = spidx->dir; 595e23731dbSKonstantin Belousov } 596e23731dbSKonstantin Belousov 597e23731dbSKonstantin Belousov static int mlx5e_if_spd_install(struct ifnet *ifp, void *sp, void *inp1, 598e23731dbSKonstantin Belousov void **ifdatap) 599e23731dbSKonstantin Belousov { 600e23731dbSKonstantin Belousov struct mlx5e_ipsec_pol_entry *pol_entry; 601e23731dbSKonstantin Belousov struct mlx5e_priv *priv; 602e23731dbSKonstantin Belousov int err; 603e23731dbSKonstantin Belousov 604e23731dbSKonstantin Belousov priv = if_getsoftc(ifp); 605e23731dbSKonstantin Belousov if (priv->gone || !priv->ipsec) 606e23731dbSKonstantin Belousov return (EOPNOTSUPP); 607e23731dbSKonstantin Belousov 608e23731dbSKonstantin Belousov err = mlx5e_xfrm_validate_policy(priv->mdev, sp, inp1); 609e23731dbSKonstantin Belousov if (err) 610e23731dbSKonstantin Belousov return err; 611e23731dbSKonstantin Belousov 612e23731dbSKonstantin Belousov pol_entry = kzalloc(sizeof(*pol_entry), GFP_KERNEL); 613e23731dbSKonstantin Belousov if (!pol_entry) 614e23731dbSKonstantin Belousov return (ENOMEM); 615e23731dbSKonstantin Belousov 616e23731dbSKonstantin Belousov pol_entry->sp = sp; 617e23731dbSKonstantin Belousov pol_entry->ipsec = priv->ipsec; 618e23731dbSKonstantin Belousov 619e23731dbSKonstantin Belousov mlx5e_ipsec_build_accel_pol_attrs(pol_entry, &pol_entry->attrs, inp1); 620e23731dbSKonstantin Belousov err = mlx5e_accel_ipsec_fs_add_pol(pol_entry); 621e23731dbSKonstantin Belousov if (err) 622e23731dbSKonstantin Belousov goto err_pol; 623e23731dbSKonstantin Belousov *ifdatap = pol_entry; 624e23731dbSKonstantin Belousov 625e23731dbSKonstantin Belousov return 0; 626e23731dbSKonstantin Belousov 627e23731dbSKonstantin Belousov err_pol: 628e23731dbSKonstantin Belousov kfree(pol_entry); 629e23731dbSKonstantin Belousov mlx5_en_err(ifp, "Device failed to offload this policy"); 630e23731dbSKonstantin Belousov return err; 631e23731dbSKonstantin Belousov } 632e23731dbSKonstantin Belousov 633e23731dbSKonstantin Belousov 634e23731dbSKonstantin Belousov static int mlx5e_if_spd_deinstall(struct ifnet *ifp, void *sp, void *ifdata) 635e23731dbSKonstantin Belousov { 636e23731dbSKonstantin Belousov struct mlx5e_ipsec_pol_entry *pol_entry = to_ipsec_pol_entry(ifdata); 637e23731dbSKonstantin Belousov 638e23731dbSKonstantin Belousov mlx5e_accel_ipsec_fs_del_pol(pol_entry); 639e23731dbSKonstantin Belousov kfree(pol_entry); 640e23731dbSKonstantin Belousov return 0; 641e23731dbSKonstantin Belousov } 642e23731dbSKonstantin Belousov 643e23731dbSKonstantin Belousov void mlx5e_ipsec_cleanup(struct mlx5e_priv *priv) 644e23731dbSKonstantin Belousov { 645e23731dbSKonstantin Belousov struct mlx5e_ipsec *pipsec = priv->ipsec; 646e23731dbSKonstantin Belousov if (!pipsec) 647e23731dbSKonstantin Belousov return; 648e23731dbSKonstantin Belousov 649e23731dbSKonstantin Belousov mlx5e_accel_ipsec_fs_cleanup(pipsec); 650e23731dbSKonstantin Belousov destroy_workqueue(pipsec->wq); 651e23731dbSKonstantin Belousov mlx5e_ipsec_aso_cleanup(pipsec); 652e23731dbSKonstantin Belousov kfree(pipsec); 653e23731dbSKonstantin Belousov priv->ipsec = NULL; 654e23731dbSKonstantin Belousov } 655e23731dbSKonstantin Belousov 656e23731dbSKonstantin Belousov static int 657e23731dbSKonstantin Belousov mlx5e_if_ipsec_hwassist(if_t ifnet, void *sav __unused, 658e23731dbSKonstantin Belousov uint32_t drv_spi __unused, void *priv __unused) 659e23731dbSKonstantin Belousov { 660e23731dbSKonstantin Belousov return (if_gethwassist(ifnet) & (CSUM_TSO | CSUM_TCP | CSUM_UDP | 661e23731dbSKonstantin Belousov CSUM_IP | CSUM_IP6_TSO | CSUM_IP6_TCP | CSUM_IP6_UDP)); 662e23731dbSKonstantin Belousov } 663e23731dbSKonstantin Belousov 664e23731dbSKonstantin Belousov static const struct if_ipsec_accel_methods mlx5e_ipsec_funcs = { 665e23731dbSKonstantin Belousov .if_sa_newkey = mlx5e_if_sa_newkey, 666e23731dbSKonstantin Belousov .if_sa_deinstall = mlx5e_if_sa_deinstall, 667e23731dbSKonstantin Belousov .if_spdadd = mlx5e_if_spd_install, 668e23731dbSKonstantin Belousov .if_spddel = mlx5e_if_spd_deinstall, 669e23731dbSKonstantin Belousov .if_sa_cnt = mlx5e_if_sa_cnt, 670e23731dbSKonstantin Belousov .if_hwassist = mlx5e_if_ipsec_hwassist, 671e23731dbSKonstantin Belousov }; 672e23731dbSKonstantin Belousov 673e23731dbSKonstantin Belousov int mlx5e_ipsec_init(struct mlx5e_priv *priv) 674e23731dbSKonstantin Belousov { 675e23731dbSKonstantin Belousov struct mlx5_core_dev *mdev = priv->mdev; 676e23731dbSKonstantin Belousov struct mlx5e_ipsec *pipsec; 677e23731dbSKonstantin Belousov if_t ifp = priv->ifp; 678e23731dbSKonstantin Belousov int ret; 679e23731dbSKonstantin Belousov 680e23731dbSKonstantin Belousov mlx5_core_info(mdev, "ipsec " 681e23731dbSKonstantin Belousov "offload %d log_max_dek %d gen_obj_types %d " 682e23731dbSKonstantin Belousov "ipsec_encrypt %d ipsec_decrypt %d " 683e23731dbSKonstantin Belousov "esp_aes_gcm_128_encrypt %d esp_aes_gcm_128_decrypt %d " 684e23731dbSKonstantin Belousov "ipsec_full_offload %d " 685e23731dbSKonstantin Belousov "reformat_add_esp_trasport %d reformat_del_esp_trasport %d " 686e23731dbSKonstantin Belousov "decap %d " 687e23731dbSKonstantin Belousov "ignore_flow_level_tx %d ignore_flow_level_rx %d " 688e23731dbSKonstantin Belousov "reformat_natt_tx %d reformat_natt_rx %d " 689e23731dbSKonstantin Belousov "ipsec_esn %d\n", 690e23731dbSKonstantin Belousov MLX5_CAP_GEN(mdev, ipsec_offload) != 0, 691e23731dbSKonstantin Belousov MLX5_CAP_GEN(mdev, log_max_dek) != 0, 692e23731dbSKonstantin Belousov (MLX5_CAP_GEN_64(mdev, general_obj_types) & 693e23731dbSKonstantin Belousov MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_IPSEC) != 0, 694e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_TX(mdev, ipsec_encrypt) != 0, 695e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_RX(mdev, ipsec_decrypt) != 0, 696e23731dbSKonstantin Belousov MLX5_CAP_IPSEC(mdev, ipsec_crypto_esp_aes_gcm_128_encrypt) != 0, 697e23731dbSKonstantin Belousov MLX5_CAP_IPSEC(mdev, ipsec_crypto_esp_aes_gcm_128_decrypt) != 0, 698e23731dbSKonstantin Belousov MLX5_CAP_IPSEC(mdev, ipsec_full_offload) != 0, 699e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_TX(mdev, reformat_add_esp_trasport) != 0, 700e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_RX(mdev, reformat_del_esp_trasport) != 0, 701e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_RX(mdev, decap) != 0, 702e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_TX(mdev, ignore_flow_level) != 0, 703e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_RX(mdev, ignore_flow_level) != 0, 704e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_TX(mdev, 705e23731dbSKonstantin Belousov reformat_add_esp_transport_over_udp) != 0, 706e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_RX(mdev, 707e23731dbSKonstantin Belousov reformat_del_esp_transport_over_udp) != 0, 708e23731dbSKonstantin Belousov MLX5_CAP_IPSEC(mdev, ipsec_esn) != 0); 709e23731dbSKonstantin Belousov 710e23731dbSKonstantin Belousov if (!(mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_PACKET_OFFLOAD)) { 711e23731dbSKonstantin Belousov mlx5_core_dbg(mdev, "Not an IPSec offload device\n"); 712e23731dbSKonstantin Belousov return 0; 713e23731dbSKonstantin Belousov } 714e23731dbSKonstantin Belousov 715e23731dbSKonstantin Belousov xa_init_flags(&mdev->ipsec_sadb, XA_FLAGS_ALLOC); 716e23731dbSKonstantin Belousov 717e23731dbSKonstantin Belousov pipsec = kzalloc(sizeof(*pipsec), GFP_KERNEL); 718e23731dbSKonstantin Belousov if (pipsec == NULL) 719e23731dbSKonstantin Belousov return (ENOMEM); 720e23731dbSKonstantin Belousov 721e23731dbSKonstantin Belousov pipsec->mdev = mdev; 722e23731dbSKonstantin Belousov pipsec->pdn = priv->pdn; 723e23731dbSKonstantin Belousov pipsec->mkey = priv->mr.key; 724e23731dbSKonstantin Belousov 725e23731dbSKonstantin Belousov ret = mlx5e_ipsec_aso_init(pipsec); 726e23731dbSKonstantin Belousov if (ret) 727e23731dbSKonstantin Belousov goto err_ipsec_aso; 728e23731dbSKonstantin Belousov 729e23731dbSKonstantin Belousov pipsec->wq = alloc_workqueue("mlx5e_ipsec", WQ_UNBOUND, 0); 730e23731dbSKonstantin Belousov if (pipsec->wq == NULL) { 731e23731dbSKonstantin Belousov ret = ENOMEM; 732e23731dbSKonstantin Belousov goto err_ipsec_wq; 733e23731dbSKonstantin Belousov } 734e23731dbSKonstantin Belousov 735e23731dbSKonstantin Belousov ret = mlx5e_accel_ipsec_fs_init(pipsec); 736e23731dbSKonstantin Belousov if (ret) 737e23731dbSKonstantin Belousov goto err_ipsec_alloc; 738e23731dbSKonstantin Belousov 739e23731dbSKonstantin Belousov if_setipsec_accel_methods(ifp, &mlx5e_ipsec_funcs); 740e23731dbSKonstantin Belousov priv->ipsec = pipsec; 741e23731dbSKonstantin Belousov mlx5_core_dbg(mdev, "IPSec attached to netdevice\n"); 742e23731dbSKonstantin Belousov return 0; 743e23731dbSKonstantin Belousov 744e23731dbSKonstantin Belousov err_ipsec_alloc: 745e23731dbSKonstantin Belousov destroy_workqueue(pipsec->wq); 746e23731dbSKonstantin Belousov err_ipsec_wq: 747e23731dbSKonstantin Belousov mlx5e_ipsec_aso_cleanup(pipsec); 748e23731dbSKonstantin Belousov err_ipsec_aso: 749e23731dbSKonstantin Belousov kfree(pipsec); 750e23731dbSKonstantin Belousov mlx5_core_err(priv->mdev, "IPSec initialization failed, %d\n", ret); 751e23731dbSKonstantin Belousov return ret; 752e23731dbSKonstantin Belousov } 753