xref: /freebsd/sys/dev/mlx5/mlx5_accel/mlx5_ipsec.c (revision e23731db48ef9c6568d4768b1f87d48514339faa)
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