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> 372851aafeSKonstantin 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 } 2612851aafeSKonstantin Belousov if (savp->state == SADB_SASTATE_DEAD) 2622851aafeSKonstantin 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*8e5b07ddSKonstantin Belousov #ifdef IPSEC_OFFLOAD 3322851aafeSKonstantin Belousov struct rm_priotracker tracker; 333*8e5b07ddSKonstantin Belousov #endif 334e23731dbSKonstantin Belousov struct mlx5e_ipsec_sa_entry *sa_entry = NULL; 335e23731dbSKonstantin Belousov struct mlx5e_priv *priv = if_getsoftc(ifp); 336e23731dbSKonstantin Belousov struct mlx5_core_dev *mdev = priv->mdev; 337e23731dbSKonstantin Belousov struct mlx5e_ipsec *ipsec = priv->ipsec; 338205263acSAriel Ehrenberg u16 vid = VLAN_NONE; 339e23731dbSKonstantin Belousov int err; 340e23731dbSKonstantin Belousov 341e23731dbSKonstantin Belousov if (priv->gone != 0 || ipsec == NULL) 342e23731dbSKonstantin Belousov return (EOPNOTSUPP); 343e23731dbSKonstantin Belousov 344205263acSAriel Ehrenberg if (if_gettype(ifpo) == IFT_L2VLAN) 345205263acSAriel Ehrenberg VLAN_TAG(ifpo, &vid); 346205263acSAriel Ehrenberg 347*8e5b07ddSKonstantin Belousov #ifdef IPSEC_OFFLOAD 3482851aafeSKonstantin Belousov ipsec_sahtree_rlock(&tracker); 349*8e5b07ddSKonstantin Belousov #endif 350e23731dbSKonstantin Belousov err = mlx5e_xfrm_validate_state(mdev, sav); 351*8e5b07ddSKonstantin Belousov #ifdef IPSEC_OFFLOAD 3522851aafeSKonstantin Belousov ipsec_sahtree_runlock(&tracker); 353*8e5b07ddSKonstantin Belousov #endif 354e23731dbSKonstantin Belousov if (err) 355e23731dbSKonstantin Belousov return err; 356e23731dbSKonstantin Belousov 357e23731dbSKonstantin Belousov sa_entry = kzalloc(sizeof(*sa_entry), GFP_KERNEL); 358e23731dbSKonstantin Belousov if (sa_entry == NULL) 359e23731dbSKonstantin Belousov return (ENOMEM); 360e23731dbSKonstantin Belousov 361e23731dbSKonstantin Belousov sa_entry->kspi = drv_spi; 362e23731dbSKonstantin Belousov sa_entry->savp = sav; 363e23731dbSKonstantin Belousov sa_entry->ifp = ifp; 364205263acSAriel Ehrenberg sa_entry->ifpo = ifpo; 365e23731dbSKonstantin Belousov sa_entry->ipsec = ipsec; 366205263acSAriel Ehrenberg sa_entry->vid = vid; 367e23731dbSKonstantin Belousov 368*8e5b07ddSKonstantin Belousov #ifdef IPSEC_OFFLOAD 3692851aafeSKonstantin Belousov ipsec_sahtree_rlock(&tracker); 370*8e5b07ddSKonstantin Belousov #endif 3712851aafeSKonstantin Belousov err = mlx5e_xfrm_validate_state(mdev, sav); 3722851aafeSKonstantin Belousov if (err != 0) { 373*8e5b07ddSKonstantin Belousov #ifdef IPSEC_OFFLOAD 3742851aafeSKonstantin Belousov ipsec_sahtree_runlock(&tracker); 375*8e5b07ddSKonstantin Belousov #endif 3762851aafeSKonstantin Belousov goto err_xfrm; 3772851aafeSKonstantin Belousov } 378e23731dbSKonstantin Belousov mlx5e_ipsec_build_accel_xfrm_attrs(sa_entry, &sa_entry->attrs, dir); 379*8e5b07ddSKonstantin Belousov #ifdef IPSEC_OFFLOAD 3802851aafeSKonstantin Belousov ipsec_sahtree_runlock(&tracker); 381*8e5b07ddSKonstantin Belousov #endif 382e23731dbSKonstantin Belousov 383e23731dbSKonstantin Belousov err = mlx5e_ipsec_create_dwork(sa_entry, pb); 384e23731dbSKonstantin Belousov if (err) 385e23731dbSKonstantin Belousov goto err_xfrm; 386e23731dbSKonstantin Belousov 387e23731dbSKonstantin Belousov /* create hw context */ 388e23731dbSKonstantin Belousov err = mlx5_ipsec_create_sa_ctx(sa_entry); 389e23731dbSKonstantin Belousov if (err) 390e23731dbSKonstantin Belousov goto err_sa_ctx; 391e23731dbSKonstantin Belousov 392e23731dbSKonstantin Belousov err = mlx5e_accel_ipsec_fs_add_rule(sa_entry); 393e23731dbSKonstantin Belousov if (err) 394e23731dbSKonstantin Belousov goto err_fs; 395e23731dbSKonstantin Belousov 396e23731dbSKonstantin Belousov *privp = sa_entry; 397e23731dbSKonstantin Belousov if (sa_entry->dwork) 398e23731dbSKonstantin Belousov queue_delayed_work(ipsec->wq, &sa_entry->dwork->dwork, MLX5_IPSEC_RESCHED); 399e23731dbSKonstantin Belousov 400e23731dbSKonstantin Belousov err = xa_insert(&mdev->ipsec_sadb, sa_entry->ipsec_obj_id, sa_entry, GFP_KERNEL); 401e23731dbSKonstantin Belousov if (err) 402e23731dbSKonstantin Belousov goto err_xa; 403e23731dbSKonstantin Belousov 404e23731dbSKonstantin Belousov return 0; 405e23731dbSKonstantin Belousov 406e23731dbSKonstantin Belousov err_xa: 407e23731dbSKonstantin Belousov if (sa_entry->dwork) 408e23731dbSKonstantin Belousov cancel_delayed_work_sync(&sa_entry->dwork->dwork); 409e23731dbSKonstantin Belousov mlx5e_accel_ipsec_fs_del_rule(sa_entry); 410e23731dbSKonstantin Belousov err_fs: 411e23731dbSKonstantin Belousov mlx5_ipsec_free_sa_ctx(sa_entry); 412e23731dbSKonstantin Belousov err_sa_ctx: 413e23731dbSKonstantin Belousov kfree(sa_entry->dwork); 414828da10bSKonstantin Belousov sa_entry->dwork = NULL; 415e23731dbSKonstantin Belousov err_xfrm: 416e23731dbSKonstantin Belousov kfree(sa_entry); 417e23731dbSKonstantin Belousov mlx5_en_err(ifp, "Device failed to offload this state"); 418e23731dbSKonstantin Belousov return err; 419e23731dbSKonstantin Belousov } 420e23731dbSKonstantin Belousov 421205263acSAriel Ehrenberg #define GET_TRUNK_IF(vifp, ifp, ept) \ 422205263acSAriel Ehrenberg if (if_gettype(vifp) == IFT_L2VLAN) { \ 423205263acSAriel Ehrenberg NET_EPOCH_ENTER(ept); \ 424205263acSAriel Ehrenberg ifp = VLAN_TRUNKDEV(vifp); \ 425205263acSAriel Ehrenberg NET_EPOCH_EXIT(ept); \ 426205263acSAriel Ehrenberg } else { \ 427205263acSAriel Ehrenberg ifp = vifp; \ 428205263acSAriel Ehrenberg } 429205263acSAriel Ehrenberg 430e23731dbSKonstantin Belousov static int 431205263acSAriel Ehrenberg mlx5e_if_sa_newkey(struct ifnet *ifpo, void *sav, u_int dev_spi, void **privp) 432e23731dbSKonstantin Belousov { 433e23731dbSKonstantin Belousov struct mlx5e_ipsec_priv_bothdir *pb; 434205263acSAriel Ehrenberg struct epoch_tracker et; 435205263acSAriel Ehrenberg struct ifnet *ifp; 436e23731dbSKonstantin Belousov int error; 437e23731dbSKonstantin Belousov 438205263acSAriel Ehrenberg GET_TRUNK_IF(ifpo, ifp, et); 439205263acSAriel Ehrenberg 440e23731dbSKonstantin Belousov pb = malloc(sizeof(struct mlx5e_ipsec_priv_bothdir), M_DEVBUF, 441e23731dbSKonstantin Belousov M_WAITOK | M_ZERO); 442205263acSAriel Ehrenberg error = mlx5e_if_sa_newkey_onedir( 443205263acSAriel Ehrenberg ifp, sav, IPSEC_DIR_INBOUND, dev_spi, &pb->priv_in, pb, ifpo); 444e23731dbSKonstantin Belousov if (error != 0) { 445e23731dbSKonstantin Belousov free(pb, M_DEVBUF); 446e23731dbSKonstantin Belousov return (error); 447e23731dbSKonstantin Belousov } 448205263acSAriel Ehrenberg error = mlx5e_if_sa_newkey_onedir( 449205263acSAriel Ehrenberg ifp, sav, IPSEC_DIR_OUTBOUND, dev_spi, &pb->priv_out, pb, ifpo); 450e23731dbSKonstantin Belousov if (error == 0) { 451e23731dbSKonstantin Belousov *privp = pb; 452e23731dbSKonstantin Belousov } else { 453828da10bSKonstantin Belousov if (pb->priv_in->dwork != NULL) 454828da10bSKonstantin Belousov cancel_delayed_work_sync(&pb->priv_in->dwork->dwork); 455828da10bSKonstantin Belousov mlx5e_if_sa_deinstall_onekey(ifp, dev_spi, pb->priv_in); 456e23731dbSKonstantin Belousov free(pb, M_DEVBUF); 457e23731dbSKonstantin Belousov } 458e23731dbSKonstantin Belousov return (error); 459e23731dbSKonstantin Belousov } 460e23731dbSKonstantin Belousov 461e23731dbSKonstantin Belousov static void 462e23731dbSKonstantin Belousov mlx5e_if_sa_deinstall_onekey(struct ifnet *ifp, u_int dev_spi, void *priv) 463e23731dbSKonstantin Belousov { 464e23731dbSKonstantin Belousov struct mlx5e_ipsec_sa_entry *sa_entry = to_ipsec_sa_entry(priv); 465e23731dbSKonstantin Belousov struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry); 466e23731dbSKonstantin Belousov struct mlx5e_ipsec_sa_entry *old; 467e23731dbSKonstantin Belousov 468e23731dbSKonstantin Belousov old = xa_erase(&mdev->ipsec_sadb, sa_entry->ipsec_obj_id); 469e23731dbSKonstantin Belousov WARN_ON(old != sa_entry); 470e23731dbSKonstantin Belousov 471e23731dbSKonstantin Belousov mlx5e_accel_ipsec_fs_del_rule(sa_entry); 472e23731dbSKonstantin Belousov mlx5_ipsec_free_sa_ctx(sa_entry); 473e23731dbSKonstantin Belousov kfree(sa_entry->dwork); 474e23731dbSKonstantin Belousov kfree(sa_entry); 475e23731dbSKonstantin Belousov } 476e23731dbSKonstantin Belousov 477e23731dbSKonstantin Belousov static int 478205263acSAriel Ehrenberg mlx5e_if_sa_deinstall(struct ifnet *ifpo, u_int dev_spi, void *priv) 479e23731dbSKonstantin Belousov { 480e23731dbSKonstantin Belousov struct mlx5e_ipsec_priv_bothdir pb, *pbp; 481205263acSAriel Ehrenberg struct epoch_tracker et; 482205263acSAriel Ehrenberg struct ifnet *ifp; 483205263acSAriel Ehrenberg 484205263acSAriel Ehrenberg GET_TRUNK_IF(ifpo, ifp, et); 485e23731dbSKonstantin Belousov 486e23731dbSKonstantin Belousov pbp = priv; 487e23731dbSKonstantin Belousov pb = *(struct mlx5e_ipsec_priv_bothdir *)priv; 488e23731dbSKonstantin Belousov pbp->priv_in = pbp->priv_out = NULL; 489e23731dbSKonstantin Belousov 490e23731dbSKonstantin Belousov if (pb.priv_in->dwork != NULL) 491e23731dbSKonstantin Belousov cancel_delayed_work_sync(&pb.priv_in->dwork->dwork); 492e23731dbSKonstantin Belousov if (pb.priv_out->dwork != NULL) 493e23731dbSKonstantin Belousov cancel_delayed_work_sync(&pb.priv_out->dwork->dwork); 494e23731dbSKonstantin Belousov 495e23731dbSKonstantin Belousov mlx5e_if_sa_deinstall_onekey(ifp, dev_spi, pb.priv_in); 496e23731dbSKonstantin Belousov mlx5e_if_sa_deinstall_onekey(ifp, dev_spi, pb.priv_out); 497e23731dbSKonstantin Belousov free(pbp, M_DEVBUF); 498e23731dbSKonstantin Belousov return (0); 499e23731dbSKonstantin Belousov } 500e23731dbSKonstantin Belousov 501e23731dbSKonstantin Belousov static void 502e23731dbSKonstantin Belousov mlx5e_if_sa_cnt_one(struct ifnet *ifp, void *sa, uint32_t drv_spi, 503e23731dbSKonstantin Belousov void *priv, u64 *bytes, u64 *packets) 504e23731dbSKonstantin Belousov { 505e23731dbSKonstantin Belousov struct mlx5e_ipsec_sa_entry *sa_entry = to_ipsec_sa_entry(priv); 506e23731dbSKonstantin Belousov struct mlx5e_ipsec_rule *ipsec_rule = &sa_entry->ipsec_rule; 507e23731dbSKonstantin Belousov struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry); 508e23731dbSKonstantin Belousov 509e23731dbSKonstantin Belousov mlx5_fc_query(mdev, ipsec_rule->fc, packets, bytes); 510e23731dbSKonstantin Belousov } 511e23731dbSKonstantin Belousov 512e23731dbSKonstantin Belousov static int 513205263acSAriel Ehrenberg mlx5e_if_sa_cnt(struct ifnet *ifpo, void *sa, uint32_t drv_spi, void *priv, 514205263acSAriel Ehrenberg struct seclifetime *lt) 515e23731dbSKonstantin Belousov { 516e23731dbSKonstantin Belousov struct mlx5e_ipsec_priv_bothdir *pb; 517e23731dbSKonstantin Belousov u64 packets_in, packets_out; 518e23731dbSKonstantin Belousov u64 bytes_in, bytes_out; 519205263acSAriel Ehrenberg struct epoch_tracker et; 520205263acSAriel Ehrenberg struct ifnet *ifp; 521205263acSAriel Ehrenberg 522205263acSAriel Ehrenberg GET_TRUNK_IF(ifpo, ifp, et); 523e23731dbSKonstantin Belousov 524e23731dbSKonstantin Belousov pb = priv; 525e23731dbSKonstantin Belousov mlx5e_if_sa_cnt_one(ifp, sa, drv_spi, pb->priv_in, 526e23731dbSKonstantin Belousov &bytes_in, &packets_in); 527e23731dbSKonstantin Belousov mlx5e_if_sa_cnt_one(ifp, sa, drv_spi, pb->priv_out, 528e23731dbSKonstantin Belousov &bytes_out, &packets_out); 529e23731dbSKonstantin Belousov /* TODO: remove this casting once Kostia changes allocation type to be u64 */ 530e23731dbSKonstantin Belousov lt->bytes = bytes_in + bytes_out; 531e23731dbSKonstantin Belousov lt->allocations = (uint32_t)(packets_in + packets_out); 532e23731dbSKonstantin Belousov return (0); 533e23731dbSKonstantin Belousov } 534e23731dbSKonstantin Belousov 535e23731dbSKonstantin Belousov static int mlx5e_xfrm_validate_policy(struct mlx5_core_dev *mdev, 536e23731dbSKonstantin Belousov struct secpolicy *sp, struct inpcb *inp) 537e23731dbSKonstantin Belousov { 538e23731dbSKonstantin Belousov struct secpolicyindex *spidx = &sp->spidx; 539e23731dbSKonstantin Belousov 540e23731dbSKonstantin Belousov if (!(mlx5_ipsec_device_caps(mdev) & 541e23731dbSKonstantin Belousov MLX5_IPSEC_CAP_PACKET_OFFLOAD)) { 542e23731dbSKonstantin Belousov mlx5_core_err(mdev, "FULL offload is not supported\n"); 543e23731dbSKonstantin Belousov return (EINVAL); 544e23731dbSKonstantin Belousov } 545e23731dbSKonstantin Belousov 546e23731dbSKonstantin Belousov if (sp->tcount > 1) { 547e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Can offload exactly one template, " 548e23731dbSKonstantin Belousov "not %d\n", sp->tcount); 549e23731dbSKonstantin Belousov return (EINVAL); 550e23731dbSKonstantin Belousov } 551e23731dbSKonstantin Belousov 552e23731dbSKonstantin Belousov if (sp->policy == IPSEC_POLICY_BYPASS && 553e23731dbSKonstantin Belousov !(mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_PRIO)) { 554e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Device does not support policy priority\n"); 555e23731dbSKonstantin Belousov return (EINVAL); 556e23731dbSKonstantin Belousov } 557e23731dbSKonstantin Belousov 558e23731dbSKonstantin Belousov if (sp->tcount > 0 && inp != NULL) { 559e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Not valid input data\n"); 560e23731dbSKonstantin Belousov return (EINVAL); 561e23731dbSKonstantin Belousov } 562e23731dbSKonstantin Belousov 563e23731dbSKonstantin Belousov if (spidx->dir != IPSEC_DIR_INBOUND && spidx->dir != IPSEC_DIR_OUTBOUND) { 564e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Wrong policy direction\n"); 565e23731dbSKonstantin Belousov return (EINVAL); 566e23731dbSKonstantin Belousov } 567e23731dbSKonstantin Belousov 568e23731dbSKonstantin Belousov if (sp->tcount > 0 && sp->req[0]->saidx.mode != IPSEC_MODE_TRANSPORT) { 569e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Device supports transport mode only"); 570e23731dbSKonstantin Belousov return (EINVAL); 571e23731dbSKonstantin Belousov } 572e23731dbSKonstantin Belousov 573e23731dbSKonstantin Belousov if (sp->policy != IPSEC_POLICY_DISCARD && 574e23731dbSKonstantin Belousov sp->policy != IPSEC_POLICY_IPSEC && sp->policy != IPSEC_POLICY_BYPASS) { 575e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Offloaded policy must be specific on its action\n"); 576e23731dbSKonstantin Belousov return (EINVAL); 577e23731dbSKonstantin Belousov } 578e23731dbSKonstantin Belousov 579e23731dbSKonstantin Belousov if (sp->policy == IPSEC_POLICY_BYPASS && !inp) { 580e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Missing port information for IKE bypass\n"); 581e23731dbSKonstantin Belousov return (EINVAL); 582e23731dbSKonstantin Belousov } 583e23731dbSKonstantin Belousov 584e23731dbSKonstantin Belousov if (inp != NULL) { 585e23731dbSKonstantin Belousov INP_RLOCK(inp); 586e23731dbSKonstantin Belousov if (inp->inp_socket == NULL || inp->inp_socket->so_proto-> 587e23731dbSKonstantin Belousov pr_protocol != IPPROTO_UDP) { 588e23731dbSKonstantin Belousov mlx5_core_err(mdev, "Unsupported IKE bypass protocol %d\n", 589e23731dbSKonstantin Belousov inp->inp_socket == NULL ? -1 : 590e23731dbSKonstantin Belousov inp->inp_socket->so_proto->pr_protocol); 591e23731dbSKonstantin Belousov INP_RUNLOCK(inp); 592e23731dbSKonstantin Belousov return (EINVAL); 593e23731dbSKonstantin Belousov } 594e23731dbSKonstantin Belousov INP_RUNLOCK(inp); 595e23731dbSKonstantin Belousov } 596e23731dbSKonstantin Belousov 597e23731dbSKonstantin Belousov /* TODO fill relevant bits */ 598e23731dbSKonstantin Belousov return 0; 599e23731dbSKonstantin Belousov } 600e23731dbSKonstantin Belousov 601205263acSAriel Ehrenberg static void 602205263acSAriel Ehrenberg mlx5e_ipsec_build_accel_pol_attrs(struct mlx5e_ipsec_pol_entry *pol_entry, 603205263acSAriel Ehrenberg struct mlx5_accel_pol_xfrm_attrs *attrs, struct inpcb *inp, u16 vid) 604e23731dbSKonstantin Belousov { 605e23731dbSKonstantin Belousov struct secpolicy *sp = pol_entry->sp; 606e23731dbSKonstantin Belousov struct secpolicyindex *spidx = &sp->spidx; 607e23731dbSKonstantin Belousov 608e23731dbSKonstantin Belousov memset(attrs, 0, sizeof(*attrs)); 609e23731dbSKonstantin Belousov 610e23731dbSKonstantin Belousov if (!inp) { 611e23731dbSKonstantin Belousov if (spidx->src.sa.sa_family == AF_INET) { 612e23731dbSKonstantin Belousov attrs->saddr.a4 = spidx->src.sin.sin_addr.s_addr; 613e23731dbSKonstantin Belousov attrs->daddr.a4 = spidx->dst.sin.sin_addr.s_addr; 614e23731dbSKonstantin Belousov } else if (spidx->src.sa.sa_family == AF_INET6) { 615e23731dbSKonstantin Belousov memcpy(&attrs->saddr.a6, &spidx->src.sin6.sin6_addr, 16); 616e23731dbSKonstantin Belousov memcpy(&attrs->daddr.a6, &spidx->dst.sin6.sin6_addr, 16); 617e23731dbSKonstantin Belousov } else { 618e23731dbSKonstantin Belousov KASSERT(0, ("unsupported family %d", spidx->src.sa.sa_family)); 619e23731dbSKonstantin Belousov } 620e23731dbSKonstantin Belousov attrs->family = spidx->src.sa.sa_family; 621e23731dbSKonstantin Belousov attrs->prio = 0; 622e23731dbSKonstantin Belousov attrs->action = sp->policy; 623e23731dbSKonstantin Belousov attrs->reqid = sp->req[0]->saidx.reqid; 624e23731dbSKonstantin Belousov } else { 625e23731dbSKonstantin Belousov INP_RLOCK(inp); 626e23731dbSKonstantin Belousov if ((inp->inp_vflag & INP_IPV4) != 0) { 627e23731dbSKonstantin Belousov attrs->saddr.a4 = inp->inp_laddr.s_addr; 628e23731dbSKonstantin Belousov attrs->daddr.a4 = inp->inp_faddr.s_addr; 629e23731dbSKonstantin Belousov attrs->family = AF_INET; 630e23731dbSKonstantin Belousov } else if ((inp->inp_vflag & INP_IPV6) != 0) { 631e23731dbSKonstantin Belousov memcpy(&attrs->saddr.a6, &inp->in6p_laddr, 16); 632e23731dbSKonstantin Belousov memcpy(&attrs->daddr.a6, &inp->in6p_laddr, 16); 633e23731dbSKonstantin Belousov attrs->family = AF_INET6; 634e23731dbSKonstantin Belousov } else { 635e23731dbSKonstantin Belousov KASSERT(0, ("unsupported family %d", inp->inp_vflag)); 636e23731dbSKonstantin Belousov } 637e23731dbSKonstantin Belousov attrs->upspec.dport = inp->inp_fport; 638e23731dbSKonstantin Belousov attrs->upspec.sport = inp->inp_lport; 639e23731dbSKonstantin Belousov attrs->upspec.proto = inp->inp_ip_p; 640e23731dbSKonstantin Belousov INP_RUNLOCK(inp); 641e23731dbSKonstantin Belousov 642e23731dbSKonstantin Belousov /* Give highest priority for PCB policies */ 643e23731dbSKonstantin Belousov attrs->prio = 1; 644e23731dbSKonstantin Belousov attrs->action = IPSEC_POLICY_IPSEC; 645e23731dbSKonstantin Belousov } 646e23731dbSKonstantin Belousov attrs->dir = spidx->dir; 647205263acSAriel Ehrenberg attrs->vid = vid; 648e23731dbSKonstantin Belousov } 649e23731dbSKonstantin Belousov 650205263acSAriel Ehrenberg static int 651205263acSAriel Ehrenberg mlx5e_if_spd_install(struct ifnet *ifpo, void *sp, void *inp1, void **ifdatap) 652e23731dbSKonstantin Belousov { 653e23731dbSKonstantin Belousov struct mlx5e_ipsec_pol_entry *pol_entry; 654e23731dbSKonstantin Belousov struct mlx5e_priv *priv; 655205263acSAriel Ehrenberg struct epoch_tracker et; 656205263acSAriel Ehrenberg u16 vid = VLAN_NONE; 657205263acSAriel Ehrenberg struct ifnet *ifp; 658e23731dbSKonstantin Belousov int err; 659e23731dbSKonstantin Belousov 660205263acSAriel Ehrenberg GET_TRUNK_IF(ifpo, ifp, et); 661205263acSAriel Ehrenberg if (if_gettype(ifpo) == IFT_L2VLAN) 662205263acSAriel Ehrenberg VLAN_TAG(ifpo, &vid); 663e23731dbSKonstantin Belousov priv = if_getsoftc(ifp); 664e23731dbSKonstantin Belousov if (priv->gone || !priv->ipsec) 665e23731dbSKonstantin Belousov return (EOPNOTSUPP); 666e23731dbSKonstantin Belousov 667e23731dbSKonstantin Belousov err = mlx5e_xfrm_validate_policy(priv->mdev, sp, inp1); 668e23731dbSKonstantin Belousov if (err) 669e23731dbSKonstantin Belousov return err; 670e23731dbSKonstantin Belousov 671e23731dbSKonstantin Belousov pol_entry = kzalloc(sizeof(*pol_entry), GFP_KERNEL); 672e23731dbSKonstantin Belousov if (!pol_entry) 673e23731dbSKonstantin Belousov return (ENOMEM); 674e23731dbSKonstantin Belousov 675e23731dbSKonstantin Belousov pol_entry->sp = sp; 676e23731dbSKonstantin Belousov pol_entry->ipsec = priv->ipsec; 677e23731dbSKonstantin Belousov 678205263acSAriel Ehrenberg mlx5e_ipsec_build_accel_pol_attrs(pol_entry, &pol_entry->attrs, 679205263acSAriel Ehrenberg inp1, vid); 680e23731dbSKonstantin Belousov err = mlx5e_accel_ipsec_fs_add_pol(pol_entry); 681e23731dbSKonstantin Belousov if (err) 682e23731dbSKonstantin Belousov goto err_pol; 683e23731dbSKonstantin Belousov *ifdatap = pol_entry; 684e23731dbSKonstantin Belousov 685e23731dbSKonstantin Belousov return 0; 686e23731dbSKonstantin Belousov 687e23731dbSKonstantin Belousov err_pol: 688e23731dbSKonstantin Belousov kfree(pol_entry); 689e23731dbSKonstantin Belousov mlx5_en_err(ifp, "Device failed to offload this policy"); 690e23731dbSKonstantin Belousov return err; 691e23731dbSKonstantin Belousov } 692e23731dbSKonstantin Belousov 693205263acSAriel Ehrenberg static int 694205263acSAriel Ehrenberg mlx5e_if_spd_deinstall(struct ifnet *ifpo, void *sp, void *ifdata) 695e23731dbSKonstantin Belousov { 696205263acSAriel Ehrenberg struct mlx5e_ipsec_pol_entry *pol_entry; 697e23731dbSKonstantin Belousov 698205263acSAriel Ehrenberg pol_entry = to_ipsec_pol_entry(ifdata); 699e23731dbSKonstantin Belousov mlx5e_accel_ipsec_fs_del_pol(pol_entry); 700e23731dbSKonstantin Belousov kfree(pol_entry); 701e23731dbSKonstantin Belousov return 0; 702e23731dbSKonstantin Belousov } 703e23731dbSKonstantin Belousov 704e23731dbSKonstantin Belousov void mlx5e_ipsec_cleanup(struct mlx5e_priv *priv) 705e23731dbSKonstantin Belousov { 706e23731dbSKonstantin Belousov struct mlx5e_ipsec *pipsec = priv->ipsec; 707e23731dbSKonstantin Belousov if (!pipsec) 708e23731dbSKonstantin Belousov return; 709e23731dbSKonstantin Belousov 710e23731dbSKonstantin Belousov mlx5e_accel_ipsec_fs_cleanup(pipsec); 711e23731dbSKonstantin Belousov destroy_workqueue(pipsec->wq); 712e23731dbSKonstantin Belousov mlx5e_ipsec_aso_cleanup(pipsec); 713e23731dbSKonstantin Belousov kfree(pipsec); 714e23731dbSKonstantin Belousov priv->ipsec = NULL; 715e23731dbSKonstantin Belousov } 716e23731dbSKonstantin Belousov 717e23731dbSKonstantin Belousov static int 718205263acSAriel Ehrenberg mlx5e_if_ipsec_hwassist(if_t ifneto, void *sav __unused, 719e23731dbSKonstantin Belousov uint32_t drv_spi __unused, void *priv __unused) 720e23731dbSKonstantin Belousov { 721205263acSAriel Ehrenberg if_t ifnet; 722205263acSAriel Ehrenberg 723205263acSAriel Ehrenberg if (if_gettype(ifneto) == IFT_L2VLAN) { 724205263acSAriel Ehrenberg ifnet = VLAN_TRUNKDEV(ifneto); 725205263acSAriel Ehrenberg } else { 726205263acSAriel Ehrenberg ifnet = ifneto; 727205263acSAriel Ehrenberg } 728205263acSAriel Ehrenberg 729e23731dbSKonstantin Belousov return (if_gethwassist(ifnet) & (CSUM_TSO | CSUM_TCP | CSUM_UDP | 730e23731dbSKonstantin Belousov CSUM_IP | CSUM_IP6_TSO | CSUM_IP6_TCP | CSUM_IP6_UDP)); 731e23731dbSKonstantin Belousov } 732e23731dbSKonstantin Belousov 733e23731dbSKonstantin Belousov static const struct if_ipsec_accel_methods mlx5e_ipsec_funcs = { 734e23731dbSKonstantin Belousov .if_sa_newkey = mlx5e_if_sa_newkey, 735e23731dbSKonstantin Belousov .if_sa_deinstall = mlx5e_if_sa_deinstall, 736e23731dbSKonstantin Belousov .if_spdadd = mlx5e_if_spd_install, 737e23731dbSKonstantin Belousov .if_spddel = mlx5e_if_spd_deinstall, 738e23731dbSKonstantin Belousov .if_sa_cnt = mlx5e_if_sa_cnt, 739e23731dbSKonstantin Belousov .if_hwassist = mlx5e_if_ipsec_hwassist, 740e23731dbSKonstantin Belousov }; 741e23731dbSKonstantin Belousov 742e23731dbSKonstantin Belousov int mlx5e_ipsec_init(struct mlx5e_priv *priv) 743e23731dbSKonstantin Belousov { 744e23731dbSKonstantin Belousov struct mlx5_core_dev *mdev = priv->mdev; 745e23731dbSKonstantin Belousov struct mlx5e_ipsec *pipsec; 746e23731dbSKonstantin Belousov if_t ifp = priv->ifp; 747e23731dbSKonstantin Belousov int ret; 748e23731dbSKonstantin Belousov 749e23731dbSKonstantin Belousov mlx5_core_info(mdev, "ipsec " 750e23731dbSKonstantin Belousov "offload %d log_max_dek %d gen_obj_types %d " 751e23731dbSKonstantin Belousov "ipsec_encrypt %d ipsec_decrypt %d " 752e23731dbSKonstantin Belousov "esp_aes_gcm_128_encrypt %d esp_aes_gcm_128_decrypt %d " 753e23731dbSKonstantin Belousov "ipsec_full_offload %d " 754e23731dbSKonstantin Belousov "reformat_add_esp_trasport %d reformat_del_esp_trasport %d " 755e23731dbSKonstantin Belousov "decap %d " 756e23731dbSKonstantin Belousov "ignore_flow_level_tx %d ignore_flow_level_rx %d " 757e23731dbSKonstantin Belousov "reformat_natt_tx %d reformat_natt_rx %d " 758e23731dbSKonstantin Belousov "ipsec_esn %d\n", 759e23731dbSKonstantin Belousov MLX5_CAP_GEN(mdev, ipsec_offload) != 0, 760e23731dbSKonstantin Belousov MLX5_CAP_GEN(mdev, log_max_dek) != 0, 761e23731dbSKonstantin Belousov (MLX5_CAP_GEN_64(mdev, general_obj_types) & 762e23731dbSKonstantin Belousov MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_IPSEC) != 0, 763e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_TX(mdev, ipsec_encrypt) != 0, 764e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_RX(mdev, ipsec_decrypt) != 0, 765e23731dbSKonstantin Belousov MLX5_CAP_IPSEC(mdev, ipsec_crypto_esp_aes_gcm_128_encrypt) != 0, 766e23731dbSKonstantin Belousov MLX5_CAP_IPSEC(mdev, ipsec_crypto_esp_aes_gcm_128_decrypt) != 0, 767e23731dbSKonstantin Belousov MLX5_CAP_IPSEC(mdev, ipsec_full_offload) != 0, 768e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_TX(mdev, reformat_add_esp_trasport) != 0, 769e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_RX(mdev, reformat_del_esp_trasport) != 0, 770e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_RX(mdev, decap) != 0, 771e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_TX(mdev, ignore_flow_level) != 0, 772e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_RX(mdev, ignore_flow_level) != 0, 773e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_TX(mdev, 774e23731dbSKonstantin Belousov reformat_add_esp_transport_over_udp) != 0, 775e23731dbSKonstantin Belousov MLX5_CAP_FLOWTABLE_NIC_RX(mdev, 776e23731dbSKonstantin Belousov reformat_del_esp_transport_over_udp) != 0, 777e23731dbSKonstantin Belousov MLX5_CAP_IPSEC(mdev, ipsec_esn) != 0); 778e23731dbSKonstantin Belousov 779e23731dbSKonstantin Belousov if (!(mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_PACKET_OFFLOAD)) { 780e23731dbSKonstantin Belousov mlx5_core_dbg(mdev, "Not an IPSec offload device\n"); 781e23731dbSKonstantin Belousov return 0; 782e23731dbSKonstantin Belousov } 783e23731dbSKonstantin Belousov 784e23731dbSKonstantin Belousov xa_init_flags(&mdev->ipsec_sadb, XA_FLAGS_ALLOC); 785e23731dbSKonstantin Belousov 786e23731dbSKonstantin Belousov pipsec = kzalloc(sizeof(*pipsec), GFP_KERNEL); 787e23731dbSKonstantin Belousov if (pipsec == NULL) 788e23731dbSKonstantin Belousov return (ENOMEM); 789e23731dbSKonstantin Belousov 790e23731dbSKonstantin Belousov pipsec->mdev = mdev; 791e23731dbSKonstantin Belousov pipsec->pdn = priv->pdn; 792e23731dbSKonstantin Belousov pipsec->mkey = priv->mr.key; 793e23731dbSKonstantin Belousov 794e23731dbSKonstantin Belousov ret = mlx5e_ipsec_aso_init(pipsec); 795e23731dbSKonstantin Belousov if (ret) 796e23731dbSKonstantin Belousov goto err_ipsec_aso; 797e23731dbSKonstantin Belousov 798e23731dbSKonstantin Belousov pipsec->wq = alloc_workqueue("mlx5e_ipsec", WQ_UNBOUND, 0); 799e23731dbSKonstantin Belousov if (pipsec->wq == NULL) { 800e23731dbSKonstantin Belousov ret = ENOMEM; 801e23731dbSKonstantin Belousov goto err_ipsec_wq; 802e23731dbSKonstantin Belousov } 803e23731dbSKonstantin Belousov 804e23731dbSKonstantin Belousov ret = mlx5e_accel_ipsec_fs_init(pipsec); 805e23731dbSKonstantin Belousov if (ret) 806e23731dbSKonstantin Belousov goto err_ipsec_alloc; 807e23731dbSKonstantin Belousov 808e23731dbSKonstantin Belousov if_setipsec_accel_methods(ifp, &mlx5e_ipsec_funcs); 809e23731dbSKonstantin Belousov priv->ipsec = pipsec; 810e23731dbSKonstantin Belousov mlx5_core_dbg(mdev, "IPSec attached to netdevice\n"); 811e23731dbSKonstantin Belousov return 0; 812e23731dbSKonstantin Belousov 813e23731dbSKonstantin Belousov err_ipsec_alloc: 814e23731dbSKonstantin Belousov destroy_workqueue(pipsec->wq); 815e23731dbSKonstantin Belousov err_ipsec_wq: 816e23731dbSKonstantin Belousov mlx5e_ipsec_aso_cleanup(pipsec); 817e23731dbSKonstantin Belousov err_ipsec_aso: 818e23731dbSKonstantin Belousov kfree(pipsec); 819e23731dbSKonstantin Belousov mlx5_core_err(priv->mdev, "IPSec initialization failed, %d\n", ret); 820e23731dbSKonstantin Belousov return ret; 821e23731dbSKonstantin Belousov } 822