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> 37*2851aafeSKonstantin Belousov #include <netipsec/key.h> 38e23731dbSKonstantin Belousov #include <netipsec/key_var.h> 39e23731dbSKonstantin Belousov #include <netipsec/keydb.h> 40e23731dbSKonstantin Belousov #include <netipsec/ipsec.h> 41e23731dbSKonstantin Belousov #include <netipsec/xform.h> 42e23731dbSKonstantin Belousov #include <netipsec/ipsec_offload.h> 43e23731dbSKonstantin Belousov #include <dev/mlx5/fs.h> 44e23731dbSKonstantin Belousov #include <dev/mlx5/mlx5_en/en.h> 45e23731dbSKonstantin Belousov #include <dev/mlx5/mlx5_accel/ipsec.h> 46e23731dbSKonstantin Belousov 47e23731dbSKonstantin Belousov #define MLX5_IPSEC_RESCHED msecs_to_jiffies(1000) 48e23731dbSKonstantin Belousov 49828da10bSKonstantin Belousov static void mlx5e_if_sa_deinstall_onekey(struct ifnet *ifp, u_int dev_spi, 50828da10bSKonstantin Belousov void *priv); 51e23731dbSKonstantin Belousov static int mlx5e_if_sa_deinstall(struct ifnet *ifp, u_int dev_spi, void *priv); 52e23731dbSKonstantin Belousov 53e23731dbSKonstantin Belousov static struct mlx5e_ipsec_sa_entry *to_ipsec_sa_entry(void *x) 54e23731dbSKonstantin Belousov { 55e23731dbSKonstantin Belousov return (struct mlx5e_ipsec_sa_entry *)x; 56e23731dbSKonstantin Belousov } 57e23731dbSKonstantin Belousov 58e23731dbSKonstantin Belousov static struct mlx5e_ipsec_pol_entry *to_ipsec_pol_entry(void *x) 59e23731dbSKonstantin Belousov { 60e23731dbSKonstantin Belousov return (struct mlx5e_ipsec_pol_entry *)x; 61e23731dbSKonstantin Belousov } 62e23731dbSKonstantin Belousov 63e23731dbSKonstantin Belousov static void 64e23731dbSKonstantin Belousov mlx5e_ipsec_handle_counters_onedir(struct mlx5e_ipsec_sa_entry *sa_entry, 65e23731dbSKonstantin Belousov u64 *packets, u64 *bytes) 66e23731dbSKonstantin Belousov { 67e23731dbSKonstantin Belousov struct mlx5e_ipsec_rule *ipsec_rule = &sa_entry->ipsec_rule; 68e23731dbSKonstantin Belousov struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry); 69e23731dbSKonstantin Belousov 70e23731dbSKonstantin Belousov mlx5_fc_query(mdev, ipsec_rule->fc, packets, bytes); 71e23731dbSKonstantin Belousov } 72e23731dbSKonstantin Belousov 73e23731dbSKonstantin Belousov static struct mlx5e_ipsec_sa_entry * 74e23731dbSKonstantin Belousov mlx5e_ipsec_other_sa_entry(struct mlx5e_ipsec_priv_bothdir *pb, 75e23731dbSKonstantin Belousov struct mlx5e_ipsec_sa_entry *sa_entry) 76e23731dbSKonstantin Belousov { 77e23731dbSKonstantin Belousov return (pb->priv_in == sa_entry ? pb->priv_out : pb->priv_in); 78e23731dbSKonstantin Belousov } 79e23731dbSKonstantin Belousov 80e23731dbSKonstantin Belousov static void 81e23731dbSKonstantin Belousov mlx5e_ipsec_handle_counters(struct work_struct *_work) 82e23731dbSKonstantin Belousov { 83e23731dbSKonstantin Belousov struct mlx5e_ipsec_dwork *dwork = 84e23731dbSKonstantin Belousov container_of(_work, struct mlx5e_ipsec_dwork, dwork.work); 85e23731dbSKonstantin Belousov struct mlx5e_ipsec_sa_entry *sa_entry = dwork->sa_entry; 86e23731dbSKonstantin Belousov struct mlx5e_ipsec_sa_entry *other_sa_entry; 87e23731dbSKonstantin Belousov u64 bytes, bytes1, packets1, packets; 88e23731dbSKonstantin Belousov 89e23731dbSKonstantin Belousov if (sa_entry->attrs.drop) 90e23731dbSKonstantin Belousov return; 91e23731dbSKonstantin Belousov other_sa_entry = mlx5e_ipsec_other_sa_entry(dwork->pb, sa_entry); 92e23731dbSKonstantin Belousov if (other_sa_entry == NULL || other_sa_entry->attrs.drop) 93e23731dbSKonstantin Belousov return; 94e23731dbSKonstantin Belousov 95e23731dbSKonstantin Belousov mlx5e_ipsec_handle_counters_onedir(sa_entry, &packets, &bytes); 96e23731dbSKonstantin Belousov mlx5e_ipsec_handle_counters_onedir(other_sa_entry, &packets1, &bytes1); 97e23731dbSKonstantin Belousov packets += packets1; 98e23731dbSKonstantin Belousov bytes += bytes1; 99e23731dbSKonstantin Belousov 100e23731dbSKonstantin Belousov #ifdef IPSEC_OFFLOAD 101205263acSAriel Ehrenberg ipsec_accel_drv_sa_lifetime_update( 102205263acSAriel Ehrenberg sa_entry->savp, sa_entry->ifpo, sa_entry->kspi, bytes, packets); 103e23731dbSKonstantin Belousov #endif 104e23731dbSKonstantin Belousov 105e23731dbSKonstantin Belousov queue_delayed_work(sa_entry->ipsec->wq, &dwork->dwork, 106e23731dbSKonstantin Belousov MLX5_IPSEC_RESCHED); 107e23731dbSKonstantin Belousov } 108e23731dbSKonstantin Belousov 109e23731dbSKonstantin Belousov static int 110e23731dbSKonstantin Belousov mlx5e_ipsec_create_dwork(struct mlx5e_ipsec_sa_entry *sa_entry, 111e23731dbSKonstantin Belousov struct mlx5e_ipsec_priv_bothdir *pb) 112e23731dbSKonstantin Belousov { 113e23731dbSKonstantin Belousov struct mlx5e_ipsec_dwork *dwork; 114e23731dbSKonstantin Belousov 115e23731dbSKonstantin Belousov dwork = kzalloc(sizeof(*dwork), GFP_KERNEL); 116e23731dbSKonstantin Belousov if (!dwork) 117e23731dbSKonstantin Belousov return (ENOMEM); 118e23731dbSKonstantin Belousov 119e23731dbSKonstantin Belousov dwork->sa_entry = sa_entry; 120e23731dbSKonstantin Belousov dwork->pb = pb; 121e23731dbSKonstantin Belousov INIT_DELAYED_WORK(&dwork->dwork, mlx5e_ipsec_handle_counters); 122e23731dbSKonstantin Belousov sa_entry->dwork = dwork; 123e23731dbSKonstantin Belousov return 0; 124e23731dbSKonstantin Belousov } 125e23731dbSKonstantin Belousov 126e23731dbSKonstantin Belousov static int mlx5_xform_ah_authsize(const struct auth_hash *esph) 127e23731dbSKonstantin Belousov { 128e23731dbSKonstantin Belousov int alen; 129e23731dbSKonstantin Belousov 130e23731dbSKonstantin Belousov if (esph == NULL) 131e23731dbSKonstantin Belousov return 0; 132e23731dbSKonstantin Belousov 133e23731dbSKonstantin Belousov switch (esph->type) { 134e23731dbSKonstantin Belousov case CRYPTO_SHA2_256_HMAC: 135e23731dbSKonstantin Belousov case CRYPTO_SHA2_384_HMAC: 136e23731dbSKonstantin Belousov case CRYPTO_SHA2_512_HMAC: 137e23731dbSKonstantin Belousov alen = esph->hashsize / 2; /* RFC4868 2.3 */ 138e23731dbSKonstantin Belousov break; 139e23731dbSKonstantin Belousov 140e23731dbSKonstantin Belousov case CRYPTO_POLY1305: 141e23731dbSKonstantin Belousov case CRYPTO_AES_NIST_GMAC: 142e23731dbSKonstantin Belousov alen = esph->hashsize; 143e23731dbSKonstantin Belousov break; 144e23731dbSKonstantin Belousov 145e23731dbSKonstantin Belousov default: 146e23731dbSKonstantin Belousov alen = AH_HMAC_HASHLEN; 147e23731dbSKonstantin Belousov break; 148e23731dbSKonstantin Belousov } 149e23731dbSKonstantin Belousov 150e23731dbSKonstantin Belousov return alen; 151e23731dbSKonstantin Belousov } 152e23731dbSKonstantin Belousov 153e23731dbSKonstantin Belousov void mlx5e_ipsec_build_accel_xfrm_attrs(struct mlx5e_ipsec_sa_entry *sa_entry, 154e23731dbSKonstantin Belousov struct mlx5_accel_esp_xfrm_attrs *attrs, 155e23731dbSKonstantin Belousov u8 dir) 156e23731dbSKonstantin Belousov { 157e23731dbSKonstantin Belousov struct secasvar *savp = sa_entry->savp; 158e23731dbSKonstantin Belousov const struct auth_hash *esph = savp->tdb_authalgxform; 159e23731dbSKonstantin Belousov struct aes_gcm_keymat *aes_gcm = &attrs->aes_gcm; 160e23731dbSKonstantin Belousov struct secasindex *saidx = &savp->sah->saidx; 161e23731dbSKonstantin Belousov struct seckey *key_encap = savp->key_enc; 162e23731dbSKonstantin Belousov int key_len; 163e23731dbSKonstantin Belousov 164e23731dbSKonstantin Belousov memset(attrs, 0, sizeof(*attrs)); 165e23731dbSKonstantin Belousov 166e23731dbSKonstantin Belousov /* subtract off the salt, RFC4106, 8.1 and RFC3686, 5.1 */ 167e23731dbSKonstantin Belousov key_len = _KEYLEN(key_encap) - SAV_ISCTRORGCM(savp) * 4 - SAV_ISCHACHA(savp) * 4; 168e23731dbSKonstantin Belousov 169e23731dbSKonstantin Belousov memcpy(aes_gcm->aes_key, key_encap->key_data, key_len); 170e23731dbSKonstantin Belousov aes_gcm->key_len = key_len; 171e23731dbSKonstantin Belousov 172e23731dbSKonstantin Belousov /* salt and seq_iv */ 173e23731dbSKonstantin Belousov aes_gcm->seq_iv = 0; 174e23731dbSKonstantin Belousov memcpy(&aes_gcm->salt, key_encap->key_data + key_len, 175e23731dbSKonstantin Belousov sizeof(aes_gcm->salt)); 176e23731dbSKonstantin Belousov 177e23731dbSKonstantin Belousov switch (savp->alg_enc) { 178e23731dbSKonstantin Belousov case SADB_X_EALG_AESGCM8: 179e23731dbSKonstantin Belousov attrs->authsize = 8 / 4; /* in dwords */ 180e23731dbSKonstantin Belousov break; 181e23731dbSKonstantin Belousov case SADB_X_EALG_AESGCM12: 182e23731dbSKonstantin Belousov attrs->authsize = 12 / 4; /* in dwords */ 183e23731dbSKonstantin Belousov break; 184e23731dbSKonstantin Belousov case SADB_X_EALG_AESGCM16: 185e23731dbSKonstantin Belousov attrs->authsize = 16 / 4; /* in dwords */ 186e23731dbSKonstantin Belousov break; 187e23731dbSKonstantin Belousov default: break; 188e23731dbSKonstantin Belousov } 189e23731dbSKonstantin Belousov 190e23731dbSKonstantin Belousov /* iv len */ 191e23731dbSKonstantin Belousov aes_gcm->icv_len = mlx5_xform_ah_authsize(esph); //TBD: check if value make sense 192e23731dbSKonstantin Belousov 193e23731dbSKonstantin Belousov attrs->dir = dir; 194e23731dbSKonstantin Belousov /* spi - host order */ 195e23731dbSKonstantin Belousov attrs->spi = ntohl(savp->spi); 196e23731dbSKonstantin Belousov attrs->family = saidx->dst.sa.sa_family; 197e23731dbSKonstantin Belousov attrs->reqid = saidx->reqid; 198e23731dbSKonstantin Belousov 199e23731dbSKonstantin Belousov if (saidx->src.sa.sa_family == AF_INET) { 200e23731dbSKonstantin Belousov attrs->saddr.a4 = saidx->src.sin.sin_addr.s_addr; 201e23731dbSKonstantin Belousov attrs->daddr.a4 = saidx->dst.sin.sin_addr.s_addr; 202e23731dbSKonstantin Belousov } else { 203e23731dbSKonstantin Belousov memcpy(&attrs->saddr.a6, &saidx->src.sin6.sin6_addr, 16); 204e23731dbSKonstantin Belousov memcpy(&attrs->daddr.a6, &saidx->dst.sin6.sin6_addr, 16); 205e23731dbSKonstantin Belousov } 206e23731dbSKonstantin Belousov 207e23731dbSKonstantin Belousov if (savp->natt) { 208e23731dbSKonstantin Belousov attrs->encap = true; 209e23731dbSKonstantin Belousov attrs->sport = savp->natt->sport; 210e23731dbSKonstantin Belousov attrs->dport = savp->natt->dport; 211e23731dbSKonstantin Belousov } 212e23731dbSKonstantin Belousov 213e23731dbSKonstantin Belousov if (savp->flags & SADB_X_SAFLAGS_ESN) { 214e23731dbSKonstantin Belousov /* We support replay window with ESN only */ 215e23731dbSKonstantin Belousov attrs->replay_esn.trigger = true; 216e23731dbSKonstantin Belousov if (sa_entry->esn_state.esn_msb) 217e23731dbSKonstantin Belousov attrs->replay_esn.esn = sa_entry->esn_state.esn; 218e23731dbSKonstantin Belousov else 219e23731dbSKonstantin Belousov /* According to RFC4303, section "3.3.3. Sequence Number Generation", 220e23731dbSKonstantin Belousov * the first packet sent using a given SA will contain a sequence 221e23731dbSKonstantin Belousov * number of 1. 222e23731dbSKonstantin Belousov */ 223e23731dbSKonstantin Belousov attrs->replay_esn.esn = max_t(u32, sa_entry->esn_state.esn, 1); 224e23731dbSKonstantin Belousov attrs->replay_esn.esn_msb = sa_entry->esn_state.esn_msb; 225e23731dbSKonstantin Belousov attrs->replay_esn.overlap = sa_entry->esn_state.overlap; 226e23731dbSKonstantin Belousov 227e23731dbSKonstantin Belousov if (savp->replay) { 228e23731dbSKonstantin Belousov switch (savp->replay->wsize) { 229e23731dbSKonstantin Belousov case 4: 230e23731dbSKonstantin Belousov attrs->replay_esn.replay_window = MLX5_IPSEC_ASO_REPLAY_WIN_32BIT; 231e23731dbSKonstantin Belousov break; 232e23731dbSKonstantin Belousov case 8: 233e23731dbSKonstantin Belousov attrs->replay_esn.replay_window = MLX5_IPSEC_ASO_REPLAY_WIN_64BIT; 234e23731dbSKonstantin Belousov break; 235e23731dbSKonstantin Belousov case 16: 236e23731dbSKonstantin Belousov attrs->replay_esn.replay_window = MLX5_IPSEC_ASO_REPLAY_WIN_128BIT; 237e23731dbSKonstantin Belousov break; 238e23731dbSKonstantin Belousov case 32: 239e23731dbSKonstantin Belousov attrs->replay_esn.replay_window = MLX5_IPSEC_ASO_REPLAY_WIN_256BIT; 240e23731dbSKonstantin Belousov break; 241e23731dbSKonstantin Belousov default: 242e23731dbSKonstantin Belousov /* Do nothing */ 243e23731dbSKonstantin Belousov break; 244e23731dbSKonstantin Belousov } 245e23731dbSKonstantin Belousov } 246e23731dbSKonstantin Belousov } 247e23731dbSKonstantin Belousov } 248e23731dbSKonstantin Belousov 249e23731dbSKonstantin Belousov static int mlx5e_xfrm_validate_state(struct mlx5_core_dev *mdev, 250e23731dbSKonstantin Belousov struct secasvar *savp) 251e23731dbSKonstantin Belousov { 252e23731dbSKonstantin Belousov struct secasindex *saidx = &savp->sah->saidx; 253e23731dbSKonstantin Belousov struct seckey *key_encp = savp->key_enc; 254e23731dbSKonstantin Belousov int keylen; 255e23731dbSKonstantin Belousov 256e23731dbSKonstantin Belousov if (!(mlx5_ipsec_device_caps(mdev) & 257e23731dbSKonstantin Belousov MLX5_IPSEC_CAP_PACKET_OFFLOAD)) { 258e23731dbSKonstantin Belousov mlx5_core_err(mdev, "FULL offload is not supported\n"); 259e23731dbSKonstantin Belousov return (EINVAL); 260e23731dbSKonstantin Belousov } 261*2851aafeSKonstantin Belousov if (savp->state == SADB_SASTATE_DEAD) 262*2851aafeSKonstantin Belousov return (EINVAL); 263e23731dbSKonstantin Belousov if (savp->alg_enc == SADB_EALG_NONE) { 264e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Cannot offload authenticated xfrm states\n"); 265e23731dbSKonstantin Belousov return (EINVAL); 266e23731dbSKonstantin Belousov } 267e23731dbSKonstantin Belousov if (savp->alg_enc != SADB_X_EALG_AESGCM16) { 268e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Only IPSec aes-gcm-16 encryption protocol may be offloaded\n"); 269e23731dbSKonstantin Belousov return (EINVAL); 270e23731dbSKonstantin Belousov } 271e23731dbSKonstantin Belousov if (savp->tdb_compalgxform) { 272e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Cannot offload compressed xfrm states\n"); 273e23731dbSKonstantin Belousov return (EINVAL); 274e23731dbSKonstantin Belousov } 275e23731dbSKonstantin Belousov if (savp->alg_auth != SADB_X_AALG_AES128GMAC && savp->alg_auth != SADB_X_AALG_AES256GMAC) { 276e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Cannot offload xfrm states with AEAD key length other than 128/256 bits\n"); 277e23731dbSKonstantin Belousov return (EINVAL); 278e23731dbSKonstantin Belousov } 279e23731dbSKonstantin Belousov if ((saidx->dst.sa.sa_family != AF_INET && saidx->dst.sa.sa_family != AF_INET6) || 280e23731dbSKonstantin Belousov (saidx->src.sa.sa_family != AF_INET && saidx->src.sa.sa_family != AF_INET6)) { 281e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Only IPv4/6 xfrm states may be offloaded\n"); 282e23731dbSKonstantin Belousov return (EINVAL); 283e23731dbSKonstantin Belousov } 284e23731dbSKonstantin Belousov if (saidx->proto != IPPROTO_ESP) { 285e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Only ESP xfrm state may be offloaded\n"); 286e23731dbSKonstantin Belousov return (EINVAL); 287e23731dbSKonstantin Belousov } 288e23731dbSKonstantin Belousov /* subtract off the salt, RFC4106, 8.1 and RFC3686, 5.1 */ 289e23731dbSKonstantin Belousov keylen = _KEYLEN(key_encp) - SAV_ISCTRORGCM(savp) * 4 - SAV_ISCHACHA(savp) * 4; 290e23731dbSKonstantin Belousov if (keylen != 128/8 && keylen != 256 / 8) { 291e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Cannot offload xfrm states with AEAD key length other than 128/256 bit\n"); 292e23731dbSKonstantin Belousov return (EINVAL); 293e23731dbSKonstantin Belousov } 294e23731dbSKonstantin Belousov 295e23731dbSKonstantin Belousov if (saidx->mode != IPSEC_MODE_TRANSPORT) { 296e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Only transport xfrm states may be offloaded in full offlaod mode\n"); 297e23731dbSKonstantin Belousov return (EINVAL); 298e23731dbSKonstantin Belousov } 299e23731dbSKonstantin Belousov 300e23731dbSKonstantin Belousov if (savp->natt) { 301e23731dbSKonstantin Belousov if (!(mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_ESPINUDP)) { 302e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Encapsulation is not supported\n"); 303e23731dbSKonstantin Belousov return (EINVAL); 304e23731dbSKonstantin Belousov } 305e23731dbSKonstantin Belousov } 306e23731dbSKonstantin Belousov 307e23731dbSKonstantin Belousov if (savp->replay && savp->replay->wsize != 0 && savp->replay->wsize != 4 && 308e23731dbSKonstantin Belousov savp->replay->wsize != 8 && savp->replay->wsize != 16 && savp->replay->wsize != 32) { 309e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Unsupported replay window size %d\n", savp->replay->wsize); 310e23731dbSKonstantin Belousov return (EINVAL); 311e23731dbSKonstantin Belousov } 312e23731dbSKonstantin Belousov 313e23731dbSKonstantin Belousov if ((savp->flags & SADB_X_SAFLAGS_ESN) != 0) { 314e23731dbSKonstantin Belousov if ((mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_ESN) == 0) { 315e23731dbSKonstantin Belousov mlx5_core_err(mdev, "ESN is not supported\n"); 316e23731dbSKonstantin Belousov return (EINVAL); 317e23731dbSKonstantin Belousov } 318e23731dbSKonstantin Belousov } else if (savp->replay != NULL && savp->replay->wsize != 0) { 319e23731dbSKonstantin Belousov mlx5_core_warn(mdev, 320e23731dbSKonstantin Belousov "non-ESN but replay-protect SA offload is not supported\n"); 321e23731dbSKonstantin Belousov return (EINVAL); 322e23731dbSKonstantin Belousov } 323e23731dbSKonstantin Belousov return 0; 324e23731dbSKonstantin Belousov } 325e23731dbSKonstantin Belousov 326e23731dbSKonstantin Belousov static int 327205263acSAriel Ehrenberg mlx5e_if_sa_newkey_onedir(struct ifnet *ifp, void *sav, int dir, u_int drv_spi, 328205263acSAriel Ehrenberg struct mlx5e_ipsec_sa_entry **privp, struct mlx5e_ipsec_priv_bothdir *pb, 329205263acSAriel Ehrenberg struct ifnet *ifpo) 330e23731dbSKonstantin Belousov { 331*2851aafeSKonstantin Belousov struct rm_priotracker tracker; 332e23731dbSKonstantin Belousov struct mlx5e_ipsec_sa_entry *sa_entry = NULL; 333e23731dbSKonstantin Belousov struct mlx5e_priv *priv = if_getsoftc(ifp); 334e23731dbSKonstantin Belousov struct mlx5_core_dev *mdev = priv->mdev; 335e23731dbSKonstantin Belousov struct mlx5e_ipsec *ipsec = priv->ipsec; 336205263acSAriel Ehrenberg u16 vid = VLAN_NONE; 337e23731dbSKonstantin Belousov int err; 338e23731dbSKonstantin Belousov 339e23731dbSKonstantin Belousov if (priv->gone != 0 || ipsec == NULL) 340e23731dbSKonstantin Belousov return (EOPNOTSUPP); 341e23731dbSKonstantin Belousov 342205263acSAriel Ehrenberg if (if_gettype(ifpo) == IFT_L2VLAN) 343205263acSAriel Ehrenberg VLAN_TAG(ifpo, &vid); 344205263acSAriel Ehrenberg 345*2851aafeSKonstantin Belousov ipsec_sahtree_rlock(&tracker); 346e23731dbSKonstantin Belousov err = mlx5e_xfrm_validate_state(mdev, sav); 347*2851aafeSKonstantin Belousov ipsec_sahtree_runlock(&tracker); 348e23731dbSKonstantin Belousov if (err) 349e23731dbSKonstantin Belousov return err; 350e23731dbSKonstantin Belousov 351e23731dbSKonstantin Belousov sa_entry = kzalloc(sizeof(*sa_entry), GFP_KERNEL); 352e23731dbSKonstantin Belousov if (sa_entry == NULL) 353e23731dbSKonstantin Belousov return (ENOMEM); 354e23731dbSKonstantin Belousov 355e23731dbSKonstantin Belousov sa_entry->kspi = drv_spi; 356e23731dbSKonstantin Belousov sa_entry->savp = sav; 357e23731dbSKonstantin Belousov sa_entry->ifp = ifp; 358205263acSAriel Ehrenberg sa_entry->ifpo = ifpo; 359e23731dbSKonstantin Belousov sa_entry->ipsec = ipsec; 360205263acSAriel Ehrenberg sa_entry->vid = vid; 361e23731dbSKonstantin Belousov 362*2851aafeSKonstantin Belousov ipsec_sahtree_rlock(&tracker); 363*2851aafeSKonstantin Belousov err = mlx5e_xfrm_validate_state(mdev, sav); 364*2851aafeSKonstantin Belousov if (err != 0) { 365*2851aafeSKonstantin Belousov ipsec_sahtree_runlock(&tracker); 366*2851aafeSKonstantin Belousov goto err_xfrm; 367*2851aafeSKonstantin Belousov } 368e23731dbSKonstantin Belousov mlx5e_ipsec_build_accel_xfrm_attrs(sa_entry, &sa_entry->attrs, dir); 369*2851aafeSKonstantin Belousov ipsec_sahtree_runlock(&tracker); 370e23731dbSKonstantin Belousov 371e23731dbSKonstantin Belousov err = mlx5e_ipsec_create_dwork(sa_entry, pb); 372e23731dbSKonstantin Belousov if (err) 373e23731dbSKonstantin Belousov goto err_xfrm; 374e23731dbSKonstantin Belousov 375e23731dbSKonstantin Belousov /* create hw context */ 376e23731dbSKonstantin Belousov err = mlx5_ipsec_create_sa_ctx(sa_entry); 377e23731dbSKonstantin Belousov if (err) 378e23731dbSKonstantin Belousov goto err_sa_ctx; 379e23731dbSKonstantin Belousov 380e23731dbSKonstantin Belousov err = mlx5e_accel_ipsec_fs_add_rule(sa_entry); 381e23731dbSKonstantin Belousov if (err) 382e23731dbSKonstantin Belousov goto err_fs; 383e23731dbSKonstantin Belousov 384e23731dbSKonstantin Belousov *privp = sa_entry; 385e23731dbSKonstantin Belousov if (sa_entry->dwork) 386e23731dbSKonstantin Belousov queue_delayed_work(ipsec->wq, &sa_entry->dwork->dwork, MLX5_IPSEC_RESCHED); 387e23731dbSKonstantin Belousov 388e23731dbSKonstantin Belousov err = xa_insert(&mdev->ipsec_sadb, sa_entry->ipsec_obj_id, sa_entry, GFP_KERNEL); 389e23731dbSKonstantin Belousov if (err) 390e23731dbSKonstantin Belousov goto err_xa; 391e23731dbSKonstantin Belousov 392e23731dbSKonstantin Belousov return 0; 393e23731dbSKonstantin Belousov 394e23731dbSKonstantin Belousov err_xa: 395e23731dbSKonstantin Belousov if (sa_entry->dwork) 396e23731dbSKonstantin Belousov cancel_delayed_work_sync(&sa_entry->dwork->dwork); 397e23731dbSKonstantin Belousov mlx5e_accel_ipsec_fs_del_rule(sa_entry); 398e23731dbSKonstantin Belousov err_fs: 399e23731dbSKonstantin Belousov mlx5_ipsec_free_sa_ctx(sa_entry); 400e23731dbSKonstantin Belousov err_sa_ctx: 401e23731dbSKonstantin Belousov kfree(sa_entry->dwork); 402828da10bSKonstantin Belousov sa_entry->dwork = NULL; 403e23731dbSKonstantin Belousov err_xfrm: 404e23731dbSKonstantin Belousov kfree(sa_entry); 405e23731dbSKonstantin Belousov mlx5_en_err(ifp, "Device failed to offload this state"); 406e23731dbSKonstantin Belousov return err; 407e23731dbSKonstantin Belousov } 408e23731dbSKonstantin Belousov 409205263acSAriel Ehrenberg #define GET_TRUNK_IF(vifp, ifp, ept) \ 410205263acSAriel Ehrenberg if (if_gettype(vifp) == IFT_L2VLAN) { \ 411205263acSAriel Ehrenberg NET_EPOCH_ENTER(ept); \ 412205263acSAriel Ehrenberg ifp = VLAN_TRUNKDEV(vifp); \ 413205263acSAriel Ehrenberg NET_EPOCH_EXIT(ept); \ 414205263acSAriel Ehrenberg } else { \ 415205263acSAriel Ehrenberg ifp = vifp; \ 416205263acSAriel Ehrenberg } 417205263acSAriel Ehrenberg 418e23731dbSKonstantin Belousov static int 419205263acSAriel Ehrenberg mlx5e_if_sa_newkey(struct ifnet *ifpo, void *sav, u_int dev_spi, void **privp) 420e23731dbSKonstantin Belousov { 421e23731dbSKonstantin Belousov struct mlx5e_ipsec_priv_bothdir *pb; 422205263acSAriel Ehrenberg struct epoch_tracker et; 423205263acSAriel Ehrenberg struct ifnet *ifp; 424e23731dbSKonstantin Belousov int error; 425e23731dbSKonstantin Belousov 426205263acSAriel Ehrenberg GET_TRUNK_IF(ifpo, ifp, et); 427205263acSAriel Ehrenberg 428e23731dbSKonstantin Belousov pb = malloc(sizeof(struct mlx5e_ipsec_priv_bothdir), M_DEVBUF, 429e23731dbSKonstantin Belousov M_WAITOK | M_ZERO); 430205263acSAriel Ehrenberg error = mlx5e_if_sa_newkey_onedir( 431205263acSAriel Ehrenberg ifp, sav, IPSEC_DIR_INBOUND, dev_spi, &pb->priv_in, pb, ifpo); 432e23731dbSKonstantin Belousov if (error != 0) { 433e23731dbSKonstantin Belousov free(pb, M_DEVBUF); 434e23731dbSKonstantin Belousov return (error); 435e23731dbSKonstantin Belousov } 436205263acSAriel Ehrenberg error = mlx5e_if_sa_newkey_onedir( 437205263acSAriel Ehrenberg ifp, sav, IPSEC_DIR_OUTBOUND, dev_spi, &pb->priv_out, pb, ifpo); 438e23731dbSKonstantin Belousov if (error == 0) { 439e23731dbSKonstantin Belousov *privp = pb; 440e23731dbSKonstantin Belousov } else { 441828da10bSKonstantin Belousov if (pb->priv_in->dwork != NULL) 442828da10bSKonstantin Belousov cancel_delayed_work_sync(&pb->priv_in->dwork->dwork); 443828da10bSKonstantin Belousov mlx5e_if_sa_deinstall_onekey(ifp, dev_spi, pb->priv_in); 444e23731dbSKonstantin Belousov free(pb, M_DEVBUF); 445e23731dbSKonstantin Belousov } 446e23731dbSKonstantin Belousov return (error); 447e23731dbSKonstantin Belousov } 448e23731dbSKonstantin Belousov 449e23731dbSKonstantin Belousov static void 450e23731dbSKonstantin Belousov mlx5e_if_sa_deinstall_onekey(struct ifnet *ifp, u_int dev_spi, void *priv) 451e23731dbSKonstantin Belousov { 452e23731dbSKonstantin Belousov struct mlx5e_ipsec_sa_entry *sa_entry = to_ipsec_sa_entry(priv); 453e23731dbSKonstantin Belousov struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry); 454e23731dbSKonstantin Belousov struct mlx5e_ipsec_sa_entry *old; 455e23731dbSKonstantin Belousov 456e23731dbSKonstantin Belousov old = xa_erase(&mdev->ipsec_sadb, sa_entry->ipsec_obj_id); 457e23731dbSKonstantin Belousov WARN_ON(old != sa_entry); 458e23731dbSKonstantin Belousov 459e23731dbSKonstantin Belousov mlx5e_accel_ipsec_fs_del_rule(sa_entry); 460e23731dbSKonstantin Belousov mlx5_ipsec_free_sa_ctx(sa_entry); 461e23731dbSKonstantin Belousov kfree(sa_entry->dwork); 462e23731dbSKonstantin Belousov kfree(sa_entry); 463e23731dbSKonstantin Belousov } 464e23731dbSKonstantin Belousov 465e23731dbSKonstantin Belousov static int 466205263acSAriel Ehrenberg mlx5e_if_sa_deinstall(struct ifnet *ifpo, u_int dev_spi, void *priv) 467e23731dbSKonstantin Belousov { 468e23731dbSKonstantin Belousov struct mlx5e_ipsec_priv_bothdir pb, *pbp; 469205263acSAriel Ehrenberg struct epoch_tracker et; 470205263acSAriel Ehrenberg struct ifnet *ifp; 471205263acSAriel Ehrenberg 472205263acSAriel Ehrenberg GET_TRUNK_IF(ifpo, ifp, et); 473e23731dbSKonstantin Belousov 474e23731dbSKonstantin Belousov pbp = priv; 475e23731dbSKonstantin Belousov pb = *(struct mlx5e_ipsec_priv_bothdir *)priv; 476e23731dbSKonstantin Belousov pbp->priv_in = pbp->priv_out = NULL; 477e23731dbSKonstantin Belousov 478e23731dbSKonstantin Belousov if (pb.priv_in->dwork != NULL) 479e23731dbSKonstantin Belousov cancel_delayed_work_sync(&pb.priv_in->dwork->dwork); 480e23731dbSKonstantin Belousov if (pb.priv_out->dwork != NULL) 481e23731dbSKonstantin Belousov cancel_delayed_work_sync(&pb.priv_out->dwork->dwork); 482e23731dbSKonstantin Belousov 483e23731dbSKonstantin Belousov mlx5e_if_sa_deinstall_onekey(ifp, dev_spi, pb.priv_in); 484e23731dbSKonstantin Belousov mlx5e_if_sa_deinstall_onekey(ifp, dev_spi, pb.priv_out); 485e23731dbSKonstantin Belousov free(pbp, M_DEVBUF); 486e23731dbSKonstantin Belousov return (0); 487e23731dbSKonstantin Belousov } 488e23731dbSKonstantin Belousov 489e23731dbSKonstantin Belousov static void 490e23731dbSKonstantin Belousov mlx5e_if_sa_cnt_one(struct ifnet *ifp, void *sa, uint32_t drv_spi, 491e23731dbSKonstantin Belousov void *priv, u64 *bytes, u64 *packets) 492e23731dbSKonstantin Belousov { 493e23731dbSKonstantin Belousov struct mlx5e_ipsec_sa_entry *sa_entry = to_ipsec_sa_entry(priv); 494e23731dbSKonstantin Belousov struct mlx5e_ipsec_rule *ipsec_rule = &sa_entry->ipsec_rule; 495e23731dbSKonstantin Belousov struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry); 496e23731dbSKonstantin Belousov 497e23731dbSKonstantin Belousov mlx5_fc_query(mdev, ipsec_rule->fc, packets, bytes); 498e23731dbSKonstantin Belousov } 499e23731dbSKonstantin Belousov 500e23731dbSKonstantin Belousov static int 501205263acSAriel Ehrenberg mlx5e_if_sa_cnt(struct ifnet *ifpo, void *sa, uint32_t drv_spi, void *priv, 502205263acSAriel Ehrenberg struct seclifetime *lt) 503e23731dbSKonstantin Belousov { 504e23731dbSKonstantin Belousov struct mlx5e_ipsec_priv_bothdir *pb; 505e23731dbSKonstantin Belousov u64 packets_in, packets_out; 506e23731dbSKonstantin Belousov u64 bytes_in, bytes_out; 507205263acSAriel Ehrenberg struct epoch_tracker et; 508205263acSAriel Ehrenberg struct ifnet *ifp; 509205263acSAriel Ehrenberg 510205263acSAriel Ehrenberg GET_TRUNK_IF(ifpo, ifp, et); 511e23731dbSKonstantin Belousov 512e23731dbSKonstantin Belousov pb = priv; 513e23731dbSKonstantin Belousov mlx5e_if_sa_cnt_one(ifp, sa, drv_spi, pb->priv_in, 514e23731dbSKonstantin Belousov &bytes_in, &packets_in); 515e23731dbSKonstantin Belousov mlx5e_if_sa_cnt_one(ifp, sa, drv_spi, pb->priv_out, 516e23731dbSKonstantin Belousov &bytes_out, &packets_out); 517e23731dbSKonstantin Belousov /* TODO: remove this casting once Kostia changes allocation type to be u64 */ 518e23731dbSKonstantin Belousov lt->bytes = bytes_in + bytes_out; 519e23731dbSKonstantin Belousov lt->allocations = (uint32_t)(packets_in + packets_out); 520e23731dbSKonstantin Belousov return (0); 521e23731dbSKonstantin Belousov } 522e23731dbSKonstantin Belousov 523e23731dbSKonstantin Belousov static int mlx5e_xfrm_validate_policy(struct mlx5_core_dev *mdev, 524e23731dbSKonstantin Belousov struct secpolicy *sp, struct inpcb *inp) 525e23731dbSKonstantin Belousov { 526e23731dbSKonstantin Belousov struct secpolicyindex *spidx = &sp->spidx; 527e23731dbSKonstantin Belousov 528e23731dbSKonstantin Belousov if (!(mlx5_ipsec_device_caps(mdev) & 529e23731dbSKonstantin Belousov MLX5_IPSEC_CAP_PACKET_OFFLOAD)) { 530e23731dbSKonstantin Belousov mlx5_core_err(mdev, "FULL offload is not supported\n"); 531e23731dbSKonstantin Belousov return (EINVAL); 532e23731dbSKonstantin Belousov } 533e23731dbSKonstantin Belousov 534e23731dbSKonstantin Belousov if (sp->tcount > 1) { 535e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Can offload exactly one template, " 536e23731dbSKonstantin Belousov "not %d\n", sp->tcount); 537e23731dbSKonstantin Belousov return (EINVAL); 538e23731dbSKonstantin Belousov } 539e23731dbSKonstantin Belousov 540e23731dbSKonstantin Belousov if (sp->policy == IPSEC_POLICY_BYPASS && 541e23731dbSKonstantin Belousov !(mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_PRIO)) { 542e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Device does not support policy priority\n"); 543e23731dbSKonstantin Belousov return (EINVAL); 544e23731dbSKonstantin Belousov } 545e23731dbSKonstantin Belousov 546e23731dbSKonstantin Belousov if (sp->tcount > 0 && inp != NULL) { 547e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Not valid input data\n"); 548e23731dbSKonstantin Belousov return (EINVAL); 549e23731dbSKonstantin Belousov } 550e23731dbSKonstantin Belousov 551e23731dbSKonstantin Belousov if (spidx->dir != IPSEC_DIR_INBOUND && spidx->dir != IPSEC_DIR_OUTBOUND) { 552e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Wrong policy direction\n"); 553e23731dbSKonstantin Belousov return (EINVAL); 554e23731dbSKonstantin Belousov } 555e23731dbSKonstantin Belousov 556e23731dbSKonstantin Belousov if (sp->tcount > 0 && sp->req[0]->saidx.mode != IPSEC_MODE_TRANSPORT) { 557e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Device supports transport mode only"); 558e23731dbSKonstantin Belousov return (EINVAL); 559e23731dbSKonstantin Belousov } 560e23731dbSKonstantin Belousov 561e23731dbSKonstantin Belousov if (sp->policy != IPSEC_POLICY_DISCARD && 562e23731dbSKonstantin Belousov sp->policy != IPSEC_POLICY_IPSEC && sp->policy != IPSEC_POLICY_BYPASS) { 563e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Offloaded policy must be specific on its action\n"); 564e23731dbSKonstantin Belousov return (EINVAL); 565e23731dbSKonstantin Belousov } 566e23731dbSKonstantin Belousov 567e23731dbSKonstantin Belousov if (sp->policy == IPSEC_POLICY_BYPASS && !inp) { 568e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Missing port information for IKE bypass\n"); 569e23731dbSKonstantin Belousov return (EINVAL); 570e23731dbSKonstantin Belousov } 571e23731dbSKonstantin Belousov 572e23731dbSKonstantin Belousov if (inp != NULL) { 573e23731dbSKonstantin Belousov INP_RLOCK(inp); 574e23731dbSKonstantin Belousov if (inp->inp_socket == NULL || inp->inp_socket->so_proto-> 575e23731dbSKonstantin Belousov pr_protocol != IPPROTO_UDP) { 576e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Unsupported IKE bypass protocol %d\n", 577e23731dbSKonstantin Belousov inp->inp_socket == NULL ? -1 : 578e23731dbSKonstantin Belousov inp->inp_socket->so_proto->pr_protocol); 579e23731dbSKonstantin Belousov INP_RUNLOCK(inp); 580e23731dbSKonstantin Belousov return (EINVAL); 581e23731dbSKonstantin Belousov } 582e23731dbSKonstantin Belousov INP_RUNLOCK(inp); 583e23731dbSKonstantin Belousov } 584e23731dbSKonstantin Belousov 585e23731dbSKonstantin Belousov /* TODO fill relevant bits */ 586e23731dbSKonstantin Belousov return 0; 587e23731dbSKonstantin Belousov } 588e23731dbSKonstantin Belousov 589205263acSAriel Ehrenberg static void 590205263acSAriel Ehrenberg mlx5e_ipsec_build_accel_pol_attrs(struct mlx5e_ipsec_pol_entry *pol_entry, 591205263acSAriel Ehrenberg struct mlx5_accel_pol_xfrm_attrs *attrs, struct inpcb *inp, u16 vid) 592e23731dbSKonstantin Belousov { 593e23731dbSKonstantin Belousov struct secpolicy *sp = pol_entry->sp; 594e23731dbSKonstantin Belousov struct secpolicyindex *spidx = &sp->spidx; 595e23731dbSKonstantin Belousov 596e23731dbSKonstantin Belousov memset(attrs, 0, sizeof(*attrs)); 597e23731dbSKonstantin Belousov 598e23731dbSKonstantin Belousov if (!inp) { 599e23731dbSKonstantin Belousov if (spidx->src.sa.sa_family == AF_INET) { 600e23731dbSKonstantin Belousov attrs->saddr.a4 = spidx->src.sin.sin_addr.s_addr; 601e23731dbSKonstantin Belousov attrs->daddr.a4 = spidx->dst.sin.sin_addr.s_addr; 602e23731dbSKonstantin Belousov } else if (spidx->src.sa.sa_family == AF_INET6) { 603e23731dbSKonstantin Belousov memcpy(&attrs->saddr.a6, &spidx->src.sin6.sin6_addr, 16); 604e23731dbSKonstantin Belousov memcpy(&attrs->daddr.a6, &spidx->dst.sin6.sin6_addr, 16); 605e23731dbSKonstantin Belousov } else { 606e23731dbSKonstantin Belousov KASSERT(0, ("unsupported family %d", spidx->src.sa.sa_family)); 607e23731dbSKonstantin Belousov } 608e23731dbSKonstantin Belousov attrs->family = spidx->src.sa.sa_family; 609e23731dbSKonstantin Belousov attrs->prio = 0; 610e23731dbSKonstantin Belousov attrs->action = sp->policy; 611e23731dbSKonstantin Belousov attrs->reqid = sp->req[0]->saidx.reqid; 612e23731dbSKonstantin Belousov } else { 613e23731dbSKonstantin Belousov INP_RLOCK(inp); 614e23731dbSKonstantin Belousov if ((inp->inp_vflag & INP_IPV4) != 0) { 615e23731dbSKonstantin Belousov attrs->saddr.a4 = inp->inp_laddr.s_addr; 616e23731dbSKonstantin Belousov attrs->daddr.a4 = inp->inp_faddr.s_addr; 617e23731dbSKonstantin Belousov attrs->family = AF_INET; 618e23731dbSKonstantin Belousov } else if ((inp->inp_vflag & INP_IPV6) != 0) { 619e23731dbSKonstantin Belousov memcpy(&attrs->saddr.a6, &inp->in6p_laddr, 16); 620e23731dbSKonstantin Belousov memcpy(&attrs->daddr.a6, &inp->in6p_laddr, 16); 621e23731dbSKonstantin Belousov attrs->family = AF_INET6; 622e23731dbSKonstantin Belousov } else { 623e23731dbSKonstantin Belousov KASSERT(0, ("unsupported family %d", inp->inp_vflag)); 624e23731dbSKonstantin Belousov } 625e23731dbSKonstantin Belousov attrs->upspec.dport = inp->inp_fport; 626e23731dbSKonstantin Belousov attrs->upspec.sport = inp->inp_lport; 627e23731dbSKonstantin Belousov attrs->upspec.proto = inp->inp_ip_p; 628e23731dbSKonstantin Belousov INP_RUNLOCK(inp); 629e23731dbSKonstantin Belousov 630e23731dbSKonstantin Belousov /* Give highest priority for PCB policies */ 631e23731dbSKonstantin Belousov attrs->prio = 1; 632e23731dbSKonstantin Belousov attrs->action = IPSEC_POLICY_IPSEC; 633e23731dbSKonstantin Belousov } 634e23731dbSKonstantin Belousov attrs->dir = spidx->dir; 635205263acSAriel Ehrenberg attrs->vid = vid; 636e23731dbSKonstantin Belousov } 637e23731dbSKonstantin Belousov 638205263acSAriel Ehrenberg static int 639205263acSAriel Ehrenberg mlx5e_if_spd_install(struct ifnet *ifpo, void *sp, void *inp1, void **ifdatap) 640e23731dbSKonstantin Belousov { 641e23731dbSKonstantin Belousov struct mlx5e_ipsec_pol_entry *pol_entry; 642e23731dbSKonstantin Belousov struct mlx5e_priv *priv; 643205263acSAriel Ehrenberg struct epoch_tracker et; 644205263acSAriel Ehrenberg u16 vid = VLAN_NONE; 645205263acSAriel Ehrenberg struct ifnet *ifp; 646e23731dbSKonstantin Belousov int err; 647e23731dbSKonstantin Belousov 648205263acSAriel Ehrenberg GET_TRUNK_IF(ifpo, ifp, et); 649205263acSAriel Ehrenberg if (if_gettype(ifpo) == IFT_L2VLAN) 650205263acSAriel Ehrenberg VLAN_TAG(ifpo, &vid); 651e23731dbSKonstantin Belousov priv = if_getsoftc(ifp); 652e23731dbSKonstantin Belousov if (priv->gone || !priv->ipsec) 653e23731dbSKonstantin Belousov return (EOPNOTSUPP); 654e23731dbSKonstantin Belousov 655e23731dbSKonstantin Belousov err = mlx5e_xfrm_validate_policy(priv->mdev, sp, inp1); 656e23731dbSKonstantin Belousov if (err) 657e23731dbSKonstantin Belousov return err; 658e23731dbSKonstantin Belousov 659e23731dbSKonstantin Belousov pol_entry = kzalloc(sizeof(*pol_entry), GFP_KERNEL); 660e23731dbSKonstantin Belousov if (!pol_entry) 661e23731dbSKonstantin Belousov return (ENOMEM); 662e23731dbSKonstantin Belousov 663e23731dbSKonstantin Belousov pol_entry->sp = sp; 664e23731dbSKonstantin Belousov pol_entry->ipsec = priv->ipsec; 665e23731dbSKonstantin Belousov 666205263acSAriel Ehrenberg mlx5e_ipsec_build_accel_pol_attrs(pol_entry, &pol_entry->attrs, 667205263acSAriel Ehrenberg inp1, vid); 668e23731dbSKonstantin Belousov err = mlx5e_accel_ipsec_fs_add_pol(pol_entry); 669e23731dbSKonstantin Belousov if (err) 670e23731dbSKonstantin Belousov goto err_pol; 671e23731dbSKonstantin Belousov *ifdatap = pol_entry; 672e23731dbSKonstantin Belousov 673e23731dbSKonstantin Belousov return 0; 674e23731dbSKonstantin Belousov 675e23731dbSKonstantin Belousov err_pol: 676e23731dbSKonstantin Belousov kfree(pol_entry); 677e23731dbSKonstantin Belousov mlx5_en_err(ifp, "Device failed to offload this policy"); 678e23731dbSKonstantin Belousov return err; 679e23731dbSKonstantin Belousov } 680e23731dbSKonstantin Belousov 681205263acSAriel Ehrenberg static int 682205263acSAriel Ehrenberg mlx5e_if_spd_deinstall(struct ifnet *ifpo, void *sp, void *ifdata) 683e23731dbSKonstantin Belousov { 684205263acSAriel Ehrenberg struct mlx5e_ipsec_pol_entry *pol_entry; 685e23731dbSKonstantin Belousov 686205263acSAriel Ehrenberg pol_entry = to_ipsec_pol_entry(ifdata); 687e23731dbSKonstantin Belousov mlx5e_accel_ipsec_fs_del_pol(pol_entry); 688e23731dbSKonstantin Belousov kfree(pol_entry); 689e23731dbSKonstantin Belousov return 0; 690e23731dbSKonstantin Belousov } 691e23731dbSKonstantin Belousov 692e23731dbSKonstantin Belousov void mlx5e_ipsec_cleanup(struct mlx5e_priv *priv) 693e23731dbSKonstantin Belousov { 694e23731dbSKonstantin Belousov struct mlx5e_ipsec *pipsec = priv->ipsec; 695e23731dbSKonstantin Belousov if (!pipsec) 696e23731dbSKonstantin Belousov return; 697e23731dbSKonstantin Belousov 698e23731dbSKonstantin Belousov mlx5e_accel_ipsec_fs_cleanup(pipsec); 699e23731dbSKonstantin Belousov destroy_workqueue(pipsec->wq); 700e23731dbSKonstantin Belousov mlx5e_ipsec_aso_cleanup(pipsec); 701e23731dbSKonstantin Belousov kfree(pipsec); 702e23731dbSKonstantin Belousov priv->ipsec = NULL; 703e23731dbSKonstantin Belousov } 704e23731dbSKonstantin Belousov 705e23731dbSKonstantin Belousov static int 706205263acSAriel Ehrenberg mlx5e_if_ipsec_hwassist(if_t ifneto, void *sav __unused, 707e23731dbSKonstantin Belousov uint32_t drv_spi __unused, void *priv __unused) 708e23731dbSKonstantin Belousov { 709205263acSAriel Ehrenberg if_t ifnet; 710205263acSAriel Ehrenberg 711205263acSAriel Ehrenberg if (if_gettype(ifneto) == IFT_L2VLAN) { 712205263acSAriel Ehrenberg ifnet = VLAN_TRUNKDEV(ifneto); 713205263acSAriel Ehrenberg } else { 714205263acSAriel Ehrenberg ifnet = ifneto; 715205263acSAriel Ehrenberg } 716205263acSAriel Ehrenberg 717e23731dbSKonstantin Belousov return (if_gethwassist(ifnet) & (CSUM_TSO | CSUM_TCP | CSUM_UDP | 718e23731dbSKonstantin Belousov CSUM_IP | CSUM_IP6_TSO | CSUM_IP6_TCP | CSUM_IP6_UDP)); 719e23731dbSKonstantin Belousov } 720e23731dbSKonstantin Belousov 721e23731dbSKonstantin Belousov static const struct if_ipsec_accel_methods mlx5e_ipsec_funcs = { 722e23731dbSKonstantin Belousov .if_sa_newkey = mlx5e_if_sa_newkey, 723e23731dbSKonstantin Belousov .if_sa_deinstall = mlx5e_if_sa_deinstall, 724e23731dbSKonstantin Belousov .if_spdadd = mlx5e_if_spd_install, 725e23731dbSKonstantin Belousov .if_spddel = mlx5e_if_spd_deinstall, 726e23731dbSKonstantin Belousov .if_sa_cnt = mlx5e_if_sa_cnt, 727e23731dbSKonstantin Belousov .if_hwassist = mlx5e_if_ipsec_hwassist, 728e23731dbSKonstantin Belousov }; 729e23731dbSKonstantin Belousov 730e23731dbSKonstantin Belousov int mlx5e_ipsec_init(struct mlx5e_priv *priv) 731e23731dbSKonstantin Belousov { 732e23731dbSKonstantin Belousov struct mlx5_core_dev *mdev = priv->mdev; 733e23731dbSKonstantin Belousov struct mlx5e_ipsec *pipsec; 734e23731dbSKonstantin Belousov if_t ifp = priv->ifp; 735e23731dbSKonstantin Belousov int ret; 736e23731dbSKonstantin Belousov 737e23731dbSKonstantin Belousov mlx5_core_info(mdev, "ipsec " 738e23731dbSKonstantin Belousov "offload %d log_max_dek %d gen_obj_types %d " 739e23731dbSKonstantin Belousov "ipsec_encrypt %d ipsec_decrypt %d " 740e23731dbSKonstantin Belousov "esp_aes_gcm_128_encrypt %d esp_aes_gcm_128_decrypt %d " 741e23731dbSKonstantin Belousov "ipsec_full_offload %d " 742e23731dbSKonstantin Belousov "reformat_add_esp_trasport %d reformat_del_esp_trasport %d " 743e23731dbSKonstantin Belousov "decap %d " 744e23731dbSKonstantin Belousov "ignore_flow_level_tx %d ignore_flow_level_rx %d " 745e23731dbSKonstantin Belousov "reformat_natt_tx %d reformat_natt_rx %d " 746e23731dbSKonstantin Belousov "ipsec_esn %d\n", 747e23731dbSKonstantin Belousov MLX5_CAP_GEN(mdev, ipsec_offload) != 0, 748e23731dbSKonstantin Belousov MLX5_CAP_GEN(mdev, log_max_dek) != 0, 749e23731dbSKonstantin Belousov (MLX5_CAP_GEN_64(mdev, general_obj_types) & 750e23731dbSKonstantin Belousov MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_IPSEC) != 0, 751e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_TX(mdev, ipsec_encrypt) != 0, 752e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_RX(mdev, ipsec_decrypt) != 0, 753e23731dbSKonstantin Belousov MLX5_CAP_IPSEC(mdev, ipsec_crypto_esp_aes_gcm_128_encrypt) != 0, 754e23731dbSKonstantin Belousov MLX5_CAP_IPSEC(mdev, ipsec_crypto_esp_aes_gcm_128_decrypt) != 0, 755e23731dbSKonstantin Belousov MLX5_CAP_IPSEC(mdev, ipsec_full_offload) != 0, 756e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_TX(mdev, reformat_add_esp_trasport) != 0, 757e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_RX(mdev, reformat_del_esp_trasport) != 0, 758e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_RX(mdev, decap) != 0, 759e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_TX(mdev, ignore_flow_level) != 0, 760e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_RX(mdev, ignore_flow_level) != 0, 761e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_TX(mdev, 762e23731dbSKonstantin Belousov reformat_add_esp_transport_over_udp) != 0, 763e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_RX(mdev, 764e23731dbSKonstantin Belousov reformat_del_esp_transport_over_udp) != 0, 765e23731dbSKonstantin Belousov MLX5_CAP_IPSEC(mdev, ipsec_esn) != 0); 766e23731dbSKonstantin Belousov 767e23731dbSKonstantin Belousov if (!(mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_PACKET_OFFLOAD)) { 768e23731dbSKonstantin Belousov mlx5_core_dbg(mdev, "Not an IPSec offload device\n"); 769e23731dbSKonstantin Belousov return 0; 770e23731dbSKonstantin Belousov } 771e23731dbSKonstantin Belousov 772e23731dbSKonstantin Belousov xa_init_flags(&mdev->ipsec_sadb, XA_FLAGS_ALLOC); 773e23731dbSKonstantin Belousov 774e23731dbSKonstantin Belousov pipsec = kzalloc(sizeof(*pipsec), GFP_KERNEL); 775e23731dbSKonstantin Belousov if (pipsec == NULL) 776e23731dbSKonstantin Belousov return (ENOMEM); 777e23731dbSKonstantin Belousov 778e23731dbSKonstantin Belousov pipsec->mdev = mdev; 779e23731dbSKonstantin Belousov pipsec->pdn = priv->pdn; 780e23731dbSKonstantin Belousov pipsec->mkey = priv->mr.key; 781e23731dbSKonstantin Belousov 782e23731dbSKonstantin Belousov ret = mlx5e_ipsec_aso_init(pipsec); 783e23731dbSKonstantin Belousov if (ret) 784e23731dbSKonstantin Belousov goto err_ipsec_aso; 785e23731dbSKonstantin Belousov 786e23731dbSKonstantin Belousov pipsec->wq = alloc_workqueue("mlx5e_ipsec", WQ_UNBOUND, 0); 787e23731dbSKonstantin Belousov if (pipsec->wq == NULL) { 788e23731dbSKonstantin Belousov ret = ENOMEM; 789e23731dbSKonstantin Belousov goto err_ipsec_wq; 790e23731dbSKonstantin Belousov } 791e23731dbSKonstantin Belousov 792e23731dbSKonstantin Belousov ret = mlx5e_accel_ipsec_fs_init(pipsec); 793e23731dbSKonstantin Belousov if (ret) 794e23731dbSKonstantin Belousov goto err_ipsec_alloc; 795e23731dbSKonstantin Belousov 796e23731dbSKonstantin Belousov if_setipsec_accel_methods(ifp, &mlx5e_ipsec_funcs); 797e23731dbSKonstantin Belousov priv->ipsec = pipsec; 798e23731dbSKonstantin Belousov mlx5_core_dbg(mdev, "IPSec attached to netdevice\n"); 799e23731dbSKonstantin Belousov return 0; 800e23731dbSKonstantin Belousov 801e23731dbSKonstantin Belousov err_ipsec_alloc: 802e23731dbSKonstantin Belousov destroy_workqueue(pipsec->wq); 803e23731dbSKonstantin Belousov err_ipsec_wq: 804e23731dbSKonstantin Belousov mlx5e_ipsec_aso_cleanup(pipsec); 805e23731dbSKonstantin Belousov err_ipsec_aso: 806e23731dbSKonstantin Belousov kfree(pipsec); 807e23731dbSKonstantin Belousov mlx5_core_err(priv->mdev, "IPSec initialization failed, %d\n", ret); 808e23731dbSKonstantin Belousov return ret; 809e23731dbSKonstantin Belousov } 810