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