lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20251121151644.1797728-2-cratiu@nvidia.com>
Date: Fri, 21 Nov 2025 17:16:43 +0200
From: Cosmin Ratiu <cratiu@...dia.com>
To: <netdev@...r.kernel.org>
CC: Jay Vosburgh <jv@...sburgh.net>, Andrew Lunn <andrew+netdev@...n.ch>,
	"David S. Miller" <davem@...emloft.net>, Eric Dumazet <edumazet@...gle.com>,
	Jakub Kicinski <kuba@...nel.org>, Paolo Abeni <pabeni@...hat.com>, "Simon
 Horman" <horms@...nel.org>, Taehee Yoo <ap420073@...il.com>, Jianbo Liu
	<jianbol@...dia.com>, Sabrina Dubroca <sd@...asysnail.net>, Steffen Klassert
	<steffen.klassert@...unet.com>, Herbert Xu <herbert@...dor.apana.org.au>,
	Leon Romanovsky <leonro@...dia.com>, Cosmin Ratiu <cratiu@...dia.com>
Subject: [RFC PATCH ipsec 1/2] xfrm: Add explicit offload_handle to some xfrm callbacks

The offload handle is an opaque driver-managed value for an xfrm_state
offload and is stored in xs->xso.offload_handle.
But drivers accessing it directly means there is a 1:1 association
between an xfrm_state and a device that state is offloaded on.

Remove that 1:1 mapping by passing offload_handle as an argument to
callbacks adding, deleting and freeing xfrm_states.

This unfortunately makes these API calls more verbose, but is necessary
in the subsequent patch to fix some unpleasant bonding ipsec bugs.

After this patch, the meaning of xs->xso.offload_handle becomes 'the
offload handle on the active device where this xfrm_state is offloaded'
which implies there can be at most one such active device. The offload
handle is still used directly in the xmit path.

Signed-off-by: Cosmin Ratiu <cratiu@...dia.com>
---
 Documentation/networking/xfrm_device.rst      | 13 +++--
 drivers/net/bonding/bond_main.c               | 57 ++++++++++++-------
 .../net/ethernet/chelsio/cxgb4/cxgb4_main.c   | 20 +++++--
 .../inline_crypto/ch_ipsec/chcr_ipsec.c       | 25 ++++----
 .../net/ethernet/intel/ixgbe/ixgbe_ipsec.c    | 47 +++++++++------
 drivers/net/ethernet/intel/ixgbevf/ipsec.c    | 18 +++---
 .../marvell/octeontx2/nic/cn10k_ipsec.c       | 13 +++--
 .../mellanox/mlx5/core/en_accel/ipsec.c       | 26 +++++----
 .../net/ethernet/netronome/nfp/crypto/ipsec.c | 10 ++--
 drivers/net/netdevsim/ipsec.c                 |  8 ++-
 include/linux/netdevice.h                     |  7 ++-
 net/xfrm/xfrm_device.c                        |  3 +-
 net/xfrm/xfrm_state.c                         |  7 ++-
 13 files changed, 159 insertions(+), 95 deletions(-)

diff --git a/Documentation/networking/xfrm_device.rst b/Documentation/networking/xfrm_device.rst
index 122204da0fff..0f9291469a5e 100644
--- a/Documentation/networking/xfrm_device.rst
+++ b/Documentation/networking/xfrm_device.rst
@@ -67,14 +67,19 @@ Callbacks to implement
         /* Crypto and Packet offload callbacks */
 	int	(*xdo_dev_state_add)(struct net_device *dev,
                                      struct xfrm_state *x,
+				     unsigned long *offload_handle,
                                      struct netlink_ext_ack *extack);
 	void	(*xdo_dev_state_delete)(struct net_device *dev,
-                                        struct xfrm_state *x);
+                                        struct xfrm_state *x,
+					unsigned long offload_handle);
 	void	(*xdo_dev_state_free)(struct net_device *dev,
-                                      struct xfrm_state *x);
+				      struct xfrm_state *x,
+				      unsigned long offload_handle);
 	bool	(*xdo_dev_offload_ok) (struct sk_buff *skb,
-				       struct xfrm_state *x);
-	void    (*xdo_dev_state_advance_esn) (struct xfrm_state *x);
+				       struct xfrm_state *x,
+				       unsigned long offload_handle);
+	void	(*xdo_dev_state_advance_esn) (struct xfrm_state *x,
+					      unsigned long offload_handle);
 	void    (*xdo_dev_state_update_stats) (struct xfrm_state *x);
 
         /* Solely packet offload callbacks */
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index e95e593cd12d..4c5b73786877 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -456,10 +456,12 @@ static struct net_device *bond_ipsec_dev(struct xfrm_state *xs)
  * bond_ipsec_add_sa - program device with a security association
  * @bond_dev: pointer to the bond net device
  * @xs: pointer to transformer state struct
+ * @offload_handle: pointer to resulting offload handle
  * @extack: extack point to fill failure reason
  **/
 static int bond_ipsec_add_sa(struct net_device *bond_dev,
 			     struct xfrm_state *xs,
+			     unsigned long *offload_handle,
 			     struct netlink_ext_ack *extack)
 {
 	struct net_device *real_dev;
@@ -497,7 +499,8 @@ static int bond_ipsec_add_sa(struct net_device *bond_dev,
 		goto out;
 	}
 
-	err = real_dev->xfrmdev_ops->xdo_dev_state_add(real_dev, xs, extack);
+	err = real_dev->xfrmdev_ops->xdo_dev_state_add(real_dev, xs,
+						       offload_handle, extack);
 	if (!err) {
 		xs->xso.real_dev = real_dev;
 		ipsec->xs = xs;
@@ -537,29 +540,33 @@ static void bond_ipsec_add_sa_all(struct bonding *bond)
 	}
 
 	list_for_each_entry(ipsec, &bond->ipsec_list, list) {
+		struct xfrm_state *xs = ipsec->xs;
+
 		/* If new state is added before ipsec_lock acquired */
-		if (ipsec->xs->xso.real_dev == real_dev)
+		if (xs->xso.real_dev == real_dev)
 			continue;
 
-		if (real_dev->xfrmdev_ops->xdo_dev_state_add(real_dev,
-							     ipsec->xs, NULL)) {
+		if (real_dev->xfrmdev_ops->xdo_dev_state_add(real_dev, xs,
+							     &xs->xso.offload_handle,
+							     NULL)) {
 			slave_warn(bond_dev, real_dev, "%s: failed to add SA\n", __func__);
 			continue;
 		}
 
-		spin_lock_bh(&ipsec->xs->lock);
+		spin_lock_bh(&xs->lock);
 		/* xs might have been killed by the user during the migration
 		 * to the new dev, but bond_ipsec_del_sa() should have done
 		 * nothing, as xso.real_dev is NULL.
 		 * Delete it from the device we just added it to. The pending
 		 * bond_ipsec_free_sa() call will do the rest of the cleanup.
 		 */
-		if (ipsec->xs->km.state == XFRM_STATE_DEAD &&
+		if (xs->km.state == XFRM_STATE_DEAD &&
 		    real_dev->xfrmdev_ops->xdo_dev_state_delete)
 			real_dev->xfrmdev_ops->xdo_dev_state_delete(real_dev,
-								    ipsec->xs);
-		ipsec->xs->xso.real_dev = real_dev;
-		spin_unlock_bh(&ipsec->xs->lock);
+								    xs,
+								    xs->xso.offload_handle);
+		xs->xso.real_dev = real_dev;
+		spin_unlock_bh(&xs->lock);
 	}
 out:
 	mutex_unlock(&bond->ipsec_lock);
@@ -569,9 +576,11 @@ static void bond_ipsec_add_sa_all(struct bonding *bond)
  * bond_ipsec_del_sa - clear out this specific SA
  * @bond_dev: pointer to the bond net device
  * @xs: pointer to transformer state struct
+ * @offload_handle: offload handle to delete
  **/
 static void bond_ipsec_del_sa(struct net_device *bond_dev,
-			      struct xfrm_state *xs)
+			      struct xfrm_state *xs,
+			      unsigned long offload_handle)
 {
 	struct net_device *real_dev;
 
@@ -587,7 +596,8 @@ static void bond_ipsec_del_sa(struct net_device *bond_dev,
 		return;
 	}
 
-	real_dev->xfrmdev_ops->xdo_dev_state_delete(real_dev, xs);
+	real_dev->xfrmdev_ops->xdo_dev_state_delete(real_dev, xs,
+						    offload_handle);
 }
 
 static void bond_ipsec_del_sa_all(struct bonding *bond)
@@ -604,7 +614,9 @@ static void bond_ipsec_del_sa_all(struct bonding *bond)
 
 	mutex_lock(&bond->ipsec_lock);
 	list_for_each_entry(ipsec, &bond->ipsec_list, list) {
-		if (!ipsec->xs->xso.real_dev)
+		struct xfrm_state *xs = ipsec->xs;
+
+		if (!xs->xso.real_dev)
 			continue;
 
 		if (!real_dev->xfrmdev_ops ||
@@ -616,23 +628,25 @@ static void bond_ipsec_del_sa_all(struct bonding *bond)
 			continue;
 		}
 
-		spin_lock_bh(&ipsec->xs->lock);
-		ipsec->xs->xso.real_dev = NULL;
+		spin_lock_bh(&xs->lock);
+		xs->xso.real_dev = NULL;
 		/* Don't double delete states killed by the user. */
-		if (ipsec->xs->km.state != XFRM_STATE_DEAD)
+		if (xs->km.state != XFRM_STATE_DEAD)
 			real_dev->xfrmdev_ops->xdo_dev_state_delete(real_dev,
-								    ipsec->xs);
-		spin_unlock_bh(&ipsec->xs->lock);
+								    xs,
+								    xs->xso.offload_handle);
+		spin_unlock_bh(&xs->lock);
 
 		if (real_dev->xfrmdev_ops->xdo_dev_state_free)
-			real_dev->xfrmdev_ops->xdo_dev_state_free(real_dev,
-								  ipsec->xs);
+			real_dev->xfrmdev_ops->xdo_dev_state_free(real_dev, xs,
+								  xs->xso.offload_handle);
 	}
 	mutex_unlock(&bond->ipsec_lock);
 }
 
 static void bond_ipsec_free_sa(struct net_device *bond_dev,
-			       struct xfrm_state *xs)
+			       struct xfrm_state *xs,
+			       unsigned long offload_handle)
 {
 	struct net_device *real_dev;
 	struct bond_ipsec *ipsec;
@@ -652,7 +666,8 @@ static void bond_ipsec_free_sa(struct net_device *bond_dev,
 	xs->xso.real_dev = NULL;
 	if (real_dev->xfrmdev_ops &&
 	    real_dev->xfrmdev_ops->xdo_dev_state_free)
-		real_dev->xfrmdev_ops->xdo_dev_state_free(real_dev, xs);
+		real_dev->xfrmdev_ops->xdo_dev_state_free(real_dev, xs,
+							  offload_handle);
 out:
 	list_for_each_entry(ipsec, &bond->ipsec_list, list) {
 		if (ipsec->xs == xs) {
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index 392723ef14e5..3db034a2db13 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -6482,9 +6482,11 @@ static const struct tlsdev_ops cxgb4_ktls_ops = {
 
 static int cxgb4_xfrm_add_state(struct net_device *dev,
 				struct xfrm_state *x,
+				unsigned long *offload_handle,
 				struct netlink_ext_ack *extack)
 {
 	struct adapter *adap = netdev2adap(dev);
+	const struct xfrmdev_ops *ops;
 	int ret;
 
 	if (!mutex_trylock(&uld_mutex)) {
@@ -6495,8 +6497,8 @@ static int cxgb4_xfrm_add_state(struct net_device *dev,
 	if (ret)
 		goto out_unlock;
 
-	ret = adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_state_add(dev, x,
-									extack);
+	ops = adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops;
+	ret = ops->xdo_dev_state_add(dev, x, offload_handle, extack);
 
 out_unlock:
 	mutex_unlock(&uld_mutex);
@@ -6504,9 +6506,11 @@ static int cxgb4_xfrm_add_state(struct net_device *dev,
 	return ret;
 }
 
-static void cxgb4_xfrm_del_state(struct net_device *dev, struct xfrm_state *x)
+static void cxgb4_xfrm_del_state(struct net_device *dev, struct xfrm_state *x,
+				 unsigned long offload_handle)
 {
 	struct adapter *adap = netdev2adap(dev);
+	const struct xfrmdev_ops *ops;
 
 	if (!mutex_trylock(&uld_mutex)) {
 		dev_dbg(adap->pdev_dev,
@@ -6516,15 +6520,18 @@ static void cxgb4_xfrm_del_state(struct net_device *dev, struct xfrm_state *x)
 	if (chcr_offload_state(adap, CXGB4_XFRMDEV_OPS))
 		goto out_unlock;
 
-	adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_state_delete(dev, x);
+	ops = adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops;
+	ops->xdo_dev_state_delete(dev, x, offload_handle);
 
 out_unlock:
 	mutex_unlock(&uld_mutex);
 }
 
-static void cxgb4_xfrm_free_state(struct net_device *dev, struct xfrm_state *x)
+static void cxgb4_xfrm_free_state(struct net_device *dev, struct xfrm_state *x,
+				  unsigned long offload_handle)
 {
 	struct adapter *adap = netdev2adap(dev);
+	const struct xfrmdev_ops *ops;
 
 	if (!mutex_trylock(&uld_mutex)) {
 		dev_dbg(adap->pdev_dev,
@@ -6534,7 +6541,8 @@ static void cxgb4_xfrm_free_state(struct net_device *dev, struct xfrm_state *x)
 	if (chcr_offload_state(adap, CXGB4_XFRMDEV_OPS))
 		goto out_unlock;
 
-	adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_state_free(dev, x);
+	ops = adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops;
+	ops->xdo_dev_state_free(dev, x, offload_handle);
 
 out_unlock:
 	mutex_unlock(&uld_mutex);
diff --git a/drivers/net/ethernet/chelsio/inline_crypto/ch_ipsec/chcr_ipsec.c b/drivers/net/ethernet/chelsio/inline_crypto/ch_ipsec/chcr_ipsec.c
index 49b57bb5fac1..90a101711a98 100644
--- a/drivers/net/ethernet/chelsio/inline_crypto/ch_ipsec/chcr_ipsec.c
+++ b/drivers/net/ethernet/chelsio/inline_crypto/ch_ipsec/chcr_ipsec.c
@@ -76,11 +76,14 @@ static int ch_ipsec_xmit(struct sk_buff *skb, struct net_device *dev);
 static void *ch_ipsec_uld_add(const struct cxgb4_lld_info *infop);
 static void ch_ipsec_advance_esn_state(struct xfrm_state *x);
 static void ch_ipsec_xfrm_free_state(struct net_device *dev,
-				     struct xfrm_state *x);
+				     struct xfrm_state *x,
+				     unsigned long offload_handle);
 static void ch_ipsec_xfrm_del_state(struct net_device *dev,
-				    struct xfrm_state *x);
+				    struct xfrm_state *x,
+				    unsigned long offload_handle);
 static int ch_ipsec_xfrm_add_state(struct net_device *dev,
 				   struct xfrm_state *x,
+				   unsigned long *offload_handle,
 				   struct netlink_ext_ack *extack);
 
 static const struct xfrmdev_ops ch_ipsec_xfrmdev_ops = {
@@ -228,6 +231,7 @@ static int ch_ipsec_setkey(struct xfrm_state *x,
  */
 static int ch_ipsec_xfrm_add_state(struct net_device *dev,
 				   struct xfrm_state *x,
+				   unsigned long *offload_handle,
 				   struct netlink_ext_ack *extack)
 {
 	struct ipsec_sa_entry *sa_entry;
@@ -306,29 +310,28 @@ static int ch_ipsec_xfrm_add_state(struct net_device *dev,
 	if (x->props.flags & XFRM_STATE_ESN)
 		sa_entry->esn = 1;
 	ch_ipsec_setkey(x, sa_entry);
-	x->xso.offload_handle = (unsigned long)sa_entry;
+	*offload_handle = (unsigned long)sa_entry;
 out:
 	return res;
 }
 
 static void ch_ipsec_xfrm_del_state(struct net_device *dev,
-				    struct xfrm_state *x)
+				    struct xfrm_state *x,
+				    unsigned long offload_handle)
 {
 	/* do nothing */
-	if (!x->xso.offload_handle)
+	if (!offload_handle)
 		return;
 }
 
 static void ch_ipsec_xfrm_free_state(struct net_device *dev,
-				     struct xfrm_state *x)
+				     struct xfrm_state *x,
+				     unsigned long offload_handle)
 {
-	struct ipsec_sa_entry *sa_entry;
-
-	if (!x->xso.offload_handle)
+	if (!offload_handle)
 		return;
 
-	sa_entry = (struct ipsec_sa_entry *)x->xso.offload_handle;
-	kfree(sa_entry);
+	kfree((struct ipsec_sa_entry *)offload_handle);
 	module_put(THIS_MODULE);
 }
 
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c
index d1f4073b36f9..385413206887 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c
@@ -9,7 +9,8 @@
 #define IXGBE_IPSEC_KEY_BITS  160
 static const char aes_gcm_name[] = "rfc4106(gcm(aes))";
 
-static void ixgbe_ipsec_del_sa(struct net_device *dev, struct xfrm_state *xs);
+static void ixgbe_ipsec_del_sa(struct net_device *dev, struct xfrm_state *xs,
+			       unsigned long offload_handle);
 
 /**
  * ixgbe_ipsec_set_tx_sa - set the Tx SA registers
@@ -321,7 +322,8 @@ void ixgbe_ipsec_restore(struct ixgbe_adapter *adapter)
 
 		if (r->used) {
 			if (r->mode & IXGBE_RXTXMOD_VF)
-				ixgbe_ipsec_del_sa(adapter->netdev, r->xs);
+				ixgbe_ipsec_del_sa(adapter->netdev, r->xs,
+						   r->xs->xso.offload_handle);
 			else
 				ixgbe_ipsec_set_rx_sa(hw, i, r->xs->id.spi,
 						      r->key, r->salt,
@@ -330,7 +332,8 @@ void ixgbe_ipsec_restore(struct ixgbe_adapter *adapter)
 
 		if (t->used) {
 			if (t->mode & IXGBE_RXTXMOD_VF)
-				ixgbe_ipsec_del_sa(adapter->netdev, t->xs);
+				ixgbe_ipsec_del_sa(adapter->netdev, t->xs,
+						   t->xs->xso.offload_handle);
 			else
 				ixgbe_ipsec_set_tx_sa(hw, i, t->key, t->salt);
 		}
@@ -560,10 +563,12 @@ static int ixgbe_ipsec_check_mgmt_ip(struct net_device *dev,
  * ixgbe_ipsec_add_sa - program device with a security association
  * @dev: pointer to device to program
  * @xs: pointer to transformer state struct
+ * @offload_handle: pointer to resulting offload handle
  * @extack: extack point to fill failure reason
  **/
 static int ixgbe_ipsec_add_sa(struct net_device *dev,
 			      struct xfrm_state *xs,
+			      unsigned long *offload_handle,
 			      struct netlink_ext_ack *extack)
 {
 	struct ixgbe_adapter *adapter = ixgbe_from_netdev(dev);
@@ -698,7 +703,7 @@ static int ixgbe_ipsec_add_sa(struct net_device *dev,
 
 		ixgbe_ipsec_set_rx_sa(hw, sa_idx, rsa.xs->id.spi, rsa.key,
 				      rsa.salt, rsa.mode, rsa.iptbl_ind);
-		xs->xso.offload_handle = sa_idx + IXGBE_IPSEC_BASE_RX_INDEX;
+		*offload_handle = sa_idx + IXGBE_IPSEC_BASE_RX_INDEX;
 
 		ipsec->num_rx_sa++;
 
@@ -739,7 +744,7 @@ static int ixgbe_ipsec_add_sa(struct net_device *dev,
 
 		ixgbe_ipsec_set_tx_sa(hw, sa_idx, tsa.key, tsa.salt);
 
-		xs->xso.offload_handle = sa_idx + IXGBE_IPSEC_BASE_TX_INDEX;
+		*offload_handle = sa_idx + IXGBE_IPSEC_BASE_TX_INDEX;
 
 		ipsec->num_tx_sa++;
 	}
@@ -757,8 +762,10 @@ static int ixgbe_ipsec_add_sa(struct net_device *dev,
  * ixgbe_ipsec_del_sa - clear out this specific SA
  * @dev: pointer to device to program
  * @xs: pointer to transformer state struct
+ * @offload_handle: offload handle to delete
  **/
-static void ixgbe_ipsec_del_sa(struct net_device *dev, struct xfrm_state *xs)
+static void ixgbe_ipsec_del_sa(struct net_device *dev, struct xfrm_state *xs,
+			       unsigned long offload_handle)
 {
 	struct ixgbe_adapter *adapter = ixgbe_from_netdev(dev);
 	struct ixgbe_ipsec *ipsec = adapter->ipsec;
@@ -770,12 +777,12 @@ static void ixgbe_ipsec_del_sa(struct net_device *dev, struct xfrm_state *xs)
 		struct rx_sa *rsa;
 		u8 ipi;
 
-		sa_idx = xs->xso.offload_handle - IXGBE_IPSEC_BASE_RX_INDEX;
+		sa_idx = offload_handle - IXGBE_IPSEC_BASE_RX_INDEX;
 		rsa = &ipsec->rx_tbl[sa_idx];
 
 		if (!rsa->used) {
 			netdev_err(dev, "Invalid Rx SA selected sa_idx=%d offload_handle=%lu\n",
-				   sa_idx, xs->xso.offload_handle);
+				   sa_idx, offload_handle);
 			return;
 		}
 
@@ -800,11 +807,11 @@ static void ixgbe_ipsec_del_sa(struct net_device *dev, struct xfrm_state *xs)
 		memset(rsa, 0, sizeof(struct rx_sa));
 		ipsec->num_rx_sa--;
 	} else {
-		sa_idx = xs->xso.offload_handle - IXGBE_IPSEC_BASE_TX_INDEX;
+		sa_idx = offload_handle - IXGBE_IPSEC_BASE_TX_INDEX;
 
 		if (!ipsec->tx_tbl[sa_idx].used) {
 			netdev_err(dev, "Invalid Tx SA selected sa_idx=%d offload_handle=%lu\n",
-				   sa_idx, xs->xso.offload_handle);
+				   sa_idx, offload_handle);
 			return;
 		}
 
@@ -833,6 +840,7 @@ static const struct xfrmdev_ops ixgbe_xfrmdev_ops = {
 void ixgbe_ipsec_vf_clear(struct ixgbe_adapter *adapter, u32 vf)
 {
 	struct ixgbe_ipsec *ipsec = adapter->ipsec;
+	struct xfrm_state *xs;
 	int i;
 
 	if (!ipsec)
@@ -843,9 +851,11 @@ void ixgbe_ipsec_vf_clear(struct ixgbe_adapter *adapter, u32 vf)
 		if (!ipsec->rx_tbl[i].used)
 			continue;
 		if (ipsec->rx_tbl[i].mode & IXGBE_RXTXMOD_VF &&
-		    ipsec->rx_tbl[i].vf == vf)
+		    ipsec->rx_tbl[i].vf == vf) {
+			xs = ipsec->rx_tbl[i].xs;
 			ixgbe_ipsec_del_sa(adapter->netdev,
-					   ipsec->rx_tbl[i].xs);
+					   xs, xs->xso.offload_handle);
+		}
 	}
 
 	/* search tx sa table */
@@ -853,9 +863,11 @@ void ixgbe_ipsec_vf_clear(struct ixgbe_adapter *adapter, u32 vf)
 		if (!ipsec->tx_tbl[i].used)
 			continue;
 		if (ipsec->tx_tbl[i].mode & IXGBE_RXTXMOD_VF &&
-		    ipsec->tx_tbl[i].vf == vf)
-			ixgbe_ipsec_del_sa(adapter->netdev,
-					   ipsec->tx_tbl[i].xs);
+		    ipsec->tx_tbl[i].vf == vf) {
+			xs = ipsec->tx_tbl[i].xs;
+			ixgbe_ipsec_del_sa(adapter->netdev, xs,
+					   xs->xso.offload_handle);
+		}
 	}
 }
 
@@ -935,7 +947,8 @@ int ixgbe_ipsec_vf_add_sa(struct ixgbe_adapter *adapter, u32 *msgbuf, u32 vf)
 	memcpy(xs->aead->alg_name, aes_gcm_name, sizeof(aes_gcm_name));
 
 	/* set up the HW offload */
-	err = ixgbe_ipsec_add_sa(adapter->netdev, xs, NULL);
+	err = ixgbe_ipsec_add_sa(adapter->netdev, xs, &xs->xso.offload_handle,
+				 NULL);
 	if (err)
 		goto err_aead;
 
@@ -1039,7 +1052,7 @@ int ixgbe_ipsec_vf_del_sa(struct ixgbe_adapter *adapter, u32 *msgbuf, u32 vf)
 		xs = ipsec->tx_tbl[sa_idx].xs;
 	}
 
-	ixgbe_ipsec_del_sa(adapter->netdev, xs);
+	ixgbe_ipsec_del_sa(adapter->netdev, xs, xs->xso.offload_handle);
 
 	/* remove the xs that was made-up in the add request */
 	kfree_sensitive(xs);
diff --git a/drivers/net/ethernet/intel/ixgbevf/ipsec.c b/drivers/net/ethernet/intel/ixgbevf/ipsec.c
index fce35924ff8b..6d5585f51991 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ipsec.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ipsec.c
@@ -259,10 +259,12 @@ static int ixgbevf_ipsec_parse_proto_keys(struct net_device *dev,
  * ixgbevf_ipsec_add_sa - program device with a security association
  * @dev: pointer to net device to program
  * @xs: pointer to transformer state struct
+ * @offload_handle: pointer to resulting offload_handle
  * @extack: extack point to fill failure reason
  **/
 static int ixgbevf_ipsec_add_sa(struct net_device *dev,
 				struct xfrm_state *xs,
+				unsigned long *offload_handle,
 				struct netlink_ext_ack *extack)
 {
 	struct ixgbevf_adapter *adapter;
@@ -344,7 +346,7 @@ static int ixgbevf_ipsec_add_sa(struct net_device *dev,
 		/* the preparations worked, so save the info */
 		memcpy(&ipsec->rx_tbl[sa_idx], &rsa, sizeof(rsa));
 
-		xs->xso.offload_handle = sa_idx + IXGBE_IPSEC_BASE_RX_INDEX;
+		*offload_handle = sa_idx + IXGBE_IPSEC_BASE_RX_INDEX;
 
 		ipsec->num_rx_sa++;
 
@@ -385,7 +387,7 @@ static int ixgbevf_ipsec_add_sa(struct net_device *dev,
 		/* the preparations worked, so save the info */
 		memcpy(&ipsec->tx_tbl[sa_idx], &tsa, sizeof(tsa));
 
-		xs->xso.offload_handle = sa_idx + IXGBE_IPSEC_BASE_TX_INDEX;
+		*offload_handle = sa_idx + IXGBE_IPSEC_BASE_TX_INDEX;
 
 		ipsec->num_tx_sa++;
 	}
@@ -397,9 +399,11 @@ static int ixgbevf_ipsec_add_sa(struct net_device *dev,
  * ixgbevf_ipsec_del_sa - clear out this specific SA
  * @dev: pointer to net device to program
  * @xs: pointer to transformer state struct
+ * @offload_handle: offload handle to remove
  **/
 static void ixgbevf_ipsec_del_sa(struct net_device *dev,
-				 struct xfrm_state *xs)
+				 struct xfrm_state *xs,
+				 unsigned long offload_handle)
 {
 	struct ixgbevf_adapter *adapter;
 	struct ixgbevf_ipsec *ipsec;
@@ -412,11 +416,11 @@ static void ixgbevf_ipsec_del_sa(struct net_device *dev,
 		return;
 
 	if (xs->xso.dir == XFRM_DEV_OFFLOAD_IN) {
-		sa_idx = xs->xso.offload_handle - IXGBE_IPSEC_BASE_RX_INDEX;
+		sa_idx = offload_handle - IXGBE_IPSEC_BASE_RX_INDEX;
 
 		if (!ipsec->rx_tbl[sa_idx].used) {
 			netdev_err(dev, "Invalid Rx SA selected sa_idx=%d offload_handle=%lu\n",
-				   sa_idx, xs->xso.offload_handle);
+				   sa_idx, offload_handle);
 			return;
 		}
 
@@ -425,11 +429,11 @@ static void ixgbevf_ipsec_del_sa(struct net_device *dev,
 		memset(&ipsec->rx_tbl[sa_idx], 0, sizeof(struct rx_sa));
 		ipsec->num_rx_sa--;
 	} else {
-		sa_idx = xs->xso.offload_handle - IXGBE_IPSEC_BASE_TX_INDEX;
+		sa_idx = offload_handle - IXGBE_IPSEC_BASE_TX_INDEX;
 
 		if (!ipsec->tx_tbl[sa_idx].used) {
 			netdev_err(dev, "Invalid Tx SA selected sa_idx=%d offload_handle=%lu\n",
-				   sa_idx, xs->xso.offload_handle);
+				   sa_idx, offload_handle);
 			return;
 		}
 
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_ipsec.c b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_ipsec.c
index 77543d472345..8f65106e5f20 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_ipsec.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_ipsec.c
@@ -665,6 +665,7 @@ static int cn10k_ipsec_inb_add_state(struct xfrm_state *x,
 
 static int cn10k_ipsec_outb_add_state(struct net_device *dev,
 				      struct xfrm_state *x,
+				      unsigned long *offload_handle,
 				      struct netlink_ext_ack *extack)
 {
 	struct cn10k_tx_sa_s *sa_entry;
@@ -692,7 +693,7 @@ static int cn10k_ipsec_outb_add_state(struct net_device *dev,
 		return err;
 	}
 
-	x->xso.offload_handle = (unsigned long)sa_info;
+	*offload_handle = (unsigned long)sa_info;
 	/* Enable static branch when first SA setup */
 	if (!pf->ipsec.outb_sa_count)
 		static_branch_enable(&cn10k_ipsec_sa_enabled);
@@ -702,15 +703,18 @@ static int cn10k_ipsec_outb_add_state(struct net_device *dev,
 
 static int cn10k_ipsec_add_state(struct net_device *dev,
 				 struct xfrm_state *x,
+				 unsigned long *offload_handle,
 				 struct netlink_ext_ack *extack)
 {
 	if (x->xso.dir == XFRM_DEV_OFFLOAD_IN)
 		return cn10k_ipsec_inb_add_state(x, extack);
 	else
-		return cn10k_ipsec_outb_add_state(dev, x, extack);
+		return cn10k_ipsec_outb_add_state(dev, x, offload_handle,
+						  extack);
 }
 
-static void cn10k_ipsec_del_state(struct net_device *dev, struct xfrm_state *x)
+static void cn10k_ipsec_del_state(struct net_device *dev, struct xfrm_state *x,
+				  unsigned long offload_handle)
 {
 	struct cn10k_tx_sa_s *sa_entry;
 	struct qmem *sa_info;
@@ -722,7 +726,7 @@ static void cn10k_ipsec_del_state(struct net_device *dev, struct xfrm_state *x)
 
 	pf = netdev_priv(dev);
 
-	sa_info = (struct qmem *)x->xso.offload_handle;
+	sa_info = (struct qmem *)offload_handle;
 	sa_entry = (struct cn10k_tx_sa_s *)sa_info->base;
 	memset(sa_entry, 0, sizeof(struct cn10k_tx_sa_s));
 	/* Disable SA in CPT h/w */
@@ -734,7 +738,6 @@ static void cn10k_ipsec_del_state(struct net_device *dev, struct xfrm_state *x)
 	if (err)
 		netdev_err(dev, "Error (%d) deleting SA\n", err);
 
-	x->xso.offload_handle = 0;
 	qmem_free(pf->dev, sa_info);
 
 	/* If no more SA's then update netdev feature for potential change
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
index 801527947c23..a83403b1101b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
@@ -47,11 +47,6 @@
 #define MLX5_IPSEC_RESCHED msecs_to_jiffies(1000)
 #define MLX5E_IPSEC_TUNNEL_SA XA_MARK_1
 
-static struct mlx5e_ipsec_sa_entry *to_ipsec_sa_entry(struct xfrm_state *x)
-{
-	return (struct mlx5e_ipsec_sa_entry *)x->xso.offload_handle;
-}
-
 static struct mlx5e_ipsec_pol_entry *to_ipsec_pol_entry(struct xfrm_policy *x)
 {
 	return (struct mlx5e_ipsec_pol_entry *)x->xdo.offload_handle;
@@ -767,6 +762,7 @@ static int mlx5e_ipsec_create_dwork(struct mlx5e_ipsec_sa_entry *sa_entry)
 
 static int mlx5e_xfrm_add_state(struct net_device *dev,
 				struct xfrm_state *x,
+				unsigned long *offload_handle,
 				struct netlink_ext_ack *extack)
 {
 	struct mlx5e_ipsec_sa_entry *sa_entry = NULL;
@@ -868,7 +864,7 @@ static int mlx5e_xfrm_add_state(struct net_device *dev,
 	}
 
 out:
-	x->xso.offload_handle = (unsigned long)sa_entry;
+	*offload_handle = (unsigned long)sa_entry;
 	if (allow_tunnel_mode)
 		mlx5_eswitch_unblock_encap(priv->mdev);
 
@@ -899,9 +895,11 @@ static int mlx5e_xfrm_add_state(struct net_device *dev,
 	return err;
 }
 
-static void mlx5e_xfrm_del_state(struct net_device *dev, struct xfrm_state *x)
+static void mlx5e_xfrm_del_state(struct net_device *dev, struct xfrm_state *x,
+				 unsigned long offload_handle)
 {
-	struct mlx5e_ipsec_sa_entry *sa_entry = to_ipsec_sa_entry(x);
+	struct mlx5e_ipsec_sa_entry *sa_entry =
+		(struct mlx5e_ipsec_sa_entry *)offload_handle;
 	struct mlx5e_ipsec *ipsec = sa_entry->ipsec;
 	struct mlx5e_ipsec_sa_entry *old;
 
@@ -912,9 +910,11 @@ static void mlx5e_xfrm_del_state(struct net_device *dev, struct xfrm_state *x)
 	WARN_ON(old != sa_entry);
 }
 
-static void mlx5e_xfrm_free_state(struct net_device *dev, struct xfrm_state *x)
+static void mlx5e_xfrm_free_state(struct net_device *dev, struct xfrm_state *x,
+				  unsigned long offload_handle)
 {
-	struct mlx5e_ipsec_sa_entry *sa_entry = to_ipsec_sa_entry(x);
+	struct mlx5e_ipsec_sa_entry *sa_entry =
+		(struct mlx5e_ipsec_sa_entry *)offload_handle;
 	struct mlx5e_ipsec *ipsec = sa_entry->ipsec;
 
 	if (x->xso.flags & XFRM_DEV_OFFLOAD_FLAG_ACQ)
@@ -1054,7 +1054,8 @@ void mlx5e_ipsec_cleanup(struct mlx5e_priv *priv)
 
 static void mlx5e_xfrm_advance_esn_state(struct xfrm_state *x)
 {
-	struct mlx5e_ipsec_sa_entry *sa_entry = to_ipsec_sa_entry(x);
+	struct mlx5e_ipsec_sa_entry *sa_entry =
+		(struct mlx5e_ipsec_sa_entry *)x->xso.offload_handle;
 	struct mlx5e_ipsec_work *work = sa_entry->work;
 	bool need_update;
 
@@ -1068,7 +1069,8 @@ static void mlx5e_xfrm_advance_esn_state(struct xfrm_state *x)
 
 static void mlx5e_xfrm_update_stats(struct xfrm_state *x)
 {
-	struct mlx5e_ipsec_sa_entry *sa_entry = to_ipsec_sa_entry(x);
+	struct mlx5e_ipsec_sa_entry *sa_entry =
+		(struct mlx5e_ipsec_sa_entry *)x->xso.offload_handle;
 	struct mlx5e_ipsec_rule *ipsec_rule = &sa_entry->ipsec_rule;
 	struct net *net = dev_net(x->xso.dev);
 	u64 trailer_packets = 0, trailer_bytes = 0;
diff --git a/drivers/net/ethernet/netronome/nfp/crypto/ipsec.c b/drivers/net/ethernet/netronome/nfp/crypto/ipsec.c
index 9e7c285eaa6b..c259c40bc867 100644
--- a/drivers/net/ethernet/netronome/nfp/crypto/ipsec.c
+++ b/drivers/net/ethernet/netronome/nfp/crypto/ipsec.c
@@ -268,6 +268,7 @@ static void set_sha2_512hmac(struct nfp_ipsec_cfg_add_sa *cfg, int *trunc_len)
 
 static int nfp_net_xfrm_add_state(struct net_device *dev,
 				  struct xfrm_state *x,
+				  unsigned long *offload_handle,
 				  struct netlink_ext_ack *extack)
 {
 	struct nfp_ipsec_cfg_mssg msg = {};
@@ -542,15 +543,16 @@ static int nfp_net_xfrm_add_state(struct net_device *dev,
 	}
 
 	/* 0 is invalid offload_handle for kernel */
-	x->xso.offload_handle = saidx + 1;
+	*offload_handle = saidx + 1;
 	return 0;
 }
 
-static void nfp_net_xfrm_del_state(struct net_device *dev, struct xfrm_state *x)
+static void nfp_net_xfrm_del_state(struct net_device *dev, struct xfrm_state *x,
+				   unsigned long offload_handle)
 {
 	struct nfp_ipsec_cfg_mssg msg = {
 		.cmd = NFP_IPSEC_CFG_MSSG_INV_SA,
-		.sa_idx = x->xso.offload_handle - 1,
+		.sa_idx = offload_handle - 1,
 	};
 	struct nfp_net *nn;
 	int err;
@@ -561,7 +563,7 @@ static void nfp_net_xfrm_del_state(struct net_device *dev, struct xfrm_state *x)
 	if (err)
 		nn_warn(nn, "Failed to invalidate SA in hardware\n");
 
-	xa_erase(&nn->xa_ipsec, x->xso.offload_handle - 1);
+	xa_erase(&nn->xa_ipsec, offload_handle - 1);
 }
 
 static const struct xfrmdev_ops nfp_net_ipsec_xfrmdev_ops = {
diff --git a/drivers/net/netdevsim/ipsec.c b/drivers/net/netdevsim/ipsec.c
index 47cdee5577d4..146dec01d0e8 100644
--- a/drivers/net/netdevsim/ipsec.c
+++ b/drivers/net/netdevsim/ipsec.c
@@ -131,6 +131,7 @@ static int nsim_ipsec_parse_proto_keys(struct net_device *dev,
 
 static int nsim_ipsec_add_sa(struct net_device *dev,
 			     struct xfrm_state *xs,
+			     unsigned long *offload_handle,
 			     struct netlink_ext_ack *extack)
 {
 	struct nsim_ipsec *ipsec;
@@ -193,19 +194,20 @@ static int nsim_ipsec_add_sa(struct net_device *dev,
 	/* the XFRM stack doesn't like offload_handle == 0,
 	 * so add a bitflag in case our array index is 0
 	 */
-	xs->xso.offload_handle = sa_idx | NSIM_IPSEC_VALID;
+	*offload_handle = sa_idx | NSIM_IPSEC_VALID;
 	ipsec->count++;
 
 	return 0;
 }
 
-static void nsim_ipsec_del_sa(struct net_device *dev, struct xfrm_state *xs)
+static void nsim_ipsec_del_sa(struct net_device *dev, struct xfrm_state *xs,
+			      unsigned long offload_handle)
 {
 	struct netdevsim *ns = netdev_priv(dev);
 	struct nsim_ipsec *ipsec = &ns->ipsec;
 	u16 sa_idx;
 
-	sa_idx = xs->xso.offload_handle & ~NSIM_IPSEC_VALID;
+	sa_idx = offload_handle & ~NSIM_IPSEC_VALID;
 	if (!ipsec->sa[sa_idx].used) {
 		netdev_err(ns->netdev, "Invalid SA for delete sa_idx=%d\n",
 			   sa_idx);
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index d1a687444b27..46045acc9a44 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1018,11 +1018,14 @@ struct netdev_bpf {
 struct xfrmdev_ops {
 	int	(*xdo_dev_state_add)(struct net_device *dev,
 				     struct xfrm_state *x,
+				     unsigned long *offload_handle,
 				     struct netlink_ext_ack *extack);
 	void	(*xdo_dev_state_delete)(struct net_device *dev,
-					struct xfrm_state *x);
+					struct xfrm_state *x,
+					unsigned long offload_handle);
 	void	(*xdo_dev_state_free)(struct net_device *dev,
-				      struct xfrm_state *x);
+				      struct xfrm_state *x,
+				      unsigned long offload_handle);
 	bool	(*xdo_dev_offload_ok) (struct sk_buff *skb,
 				       struct xfrm_state *x);
 	void	(*xdo_dev_state_advance_esn) (struct xfrm_state *x);
diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c
index 44b9de6e4e77..5c60ca36e586 100644
--- a/net/xfrm/xfrm_device.c
+++ b/net/xfrm/xfrm_device.c
@@ -325,7 +325,8 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
 	else
 		xso->type = XFRM_DEV_OFFLOAD_CRYPTO;
 
-	err = dev->xfrmdev_ops->xdo_dev_state_add(dev, x, extack);
+	err = dev->xfrmdev_ops->xdo_dev_state_add(dev, x, &xso->offload_handle,
+						  extack);
 	if (err) {
 		xso->dev = NULL;
 		xso->dir = 0;
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index d213ca3653a8..56bf824ec7a1 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -767,7 +767,8 @@ void xfrm_dev_state_delete(struct xfrm_state *x)
 	struct net_device *dev = READ_ONCE(xso->dev);
 
 	if (dev) {
-		dev->xfrmdev_ops->xdo_dev_state_delete(dev, x);
+		dev->xfrmdev_ops->xdo_dev_state_delete(dev, x,
+						       xso->offload_handle);
 		spin_lock_bh(&xfrm_state_dev_gc_lock);
 		hlist_add_head(&x->dev_gclist, &xfrm_state_dev_gc_list);
 		spin_unlock_bh(&xfrm_state_dev_gc_lock);
@@ -787,7 +788,8 @@ void xfrm_dev_state_free(struct xfrm_state *x)
 		spin_unlock_bh(&xfrm_state_dev_gc_lock);
 
 		if (dev->xfrmdev_ops->xdo_dev_state_free)
-			dev->xfrmdev_ops->xdo_dev_state_free(dev, x);
+			dev->xfrmdev_ops->xdo_dev_state_free(dev, x,
+							     xso->offload_handle);
 		WRITE_ONCE(xso->dev, NULL);
 		xso->type = XFRM_DEV_OFFLOAD_UNSPECIFIED;
 		netdev_put(dev, &xso->dev_tracker);
@@ -1542,6 +1544,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
 			xso->flags = XFRM_DEV_OFFLOAD_FLAG_ACQ;
 			netdev_hold(dev, &xso->dev_tracker, GFP_ATOMIC);
 			error = dev->xfrmdev_ops->xdo_dev_state_add(dev, x,
+								    &xso->offload_handle,
 								    NULL);
 			if (error) {
 				xso->dir = 0;
-- 
2.45.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ