Commit 43eca05b authored by Cosmin Ratiu's avatar Cosmin Ratiu Committed by Steffen Klassert
Browse files

xfrm: Add explicit dev to .xdo_dev_state_{add,delete,free}



Previously, device driver IPSec offload implementations would fall into
two categories:
1. Those that used xso.dev to determine the offload device.
2. Those that used xso.real_dev to determine the offload device.

The first category didn't work with bonding while the second did.
In a non-bonding setup the two pointers are the same.

This commit adds explicit pointers for the offload netdevice to
.xdo_dev_state_add() / .xdo_dev_state_delete() / .xdo_dev_state_free()
which eliminates the confusion and allows drivers from the first
category to work with bonding.

xso.real_dev now becomes a private pointer managed by the bonding
driver.

Signed-off-by: default avatarCosmin Ratiu <cratiu@nvidia.com>
Reviewed-by: default avatarLeon Romanovsky <leonro@nvidia.com>
Reviewed-by: default avatarNikolay Aleksandrov <razor@blackwall.org>
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
parent d53dda29
Loading
Loading
Loading
Loading
+7 −3
Original line number Diff line number Diff line
@@ -65,9 +65,13 @@ Callbacks to implement
  /* from include/linux/netdevice.h */
  struct xfrmdev_ops {
        /* Crypto and Packet offload callbacks */
	int	(*xdo_dev_state_add) (struct xfrm_state *x, struct netlink_ext_ack *extack);
	void	(*xdo_dev_state_delete) (struct xfrm_state *x);
	void	(*xdo_dev_state_free) (struct xfrm_state *x);
	int	(*xdo_dev_state_add)(struct net_device *dev,
                                     struct xfrm_state *x,
                                     struct netlink_ext_ack *extack);
	void	(*xdo_dev_state_delete)(struct net_device *dev,
                                        struct xfrm_state *x);
	void	(*xdo_dev_state_free)(struct net_device *dev,
                                      struct xfrm_state *x);
	bool	(*xdo_dev_offload_ok) (struct sk_buff *skb,
				       struct xfrm_state *x);
	void    (*xdo_dev_state_advance_esn) (struct xfrm_state *x);
+19 −14
Original line number Diff line number Diff line
@@ -453,13 +453,14 @@ 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
 * @extack: extack point to fill failure reason
 **/
static int bond_ipsec_add_sa(struct xfrm_state *xs,
static int bond_ipsec_add_sa(struct net_device *bond_dev,
			     struct xfrm_state *xs,
			     struct netlink_ext_ack *extack)
{
	struct net_device *bond_dev = xs->xso.dev;
	struct net_device *real_dev;
	netdevice_tracker tracker;
	struct bond_ipsec *ipsec;
@@ -496,7 +497,7 @@ static int bond_ipsec_add_sa(struct xfrm_state *xs,
	}

	xs->xso.real_dev = real_dev;
	err = real_dev->xfrmdev_ops->xdo_dev_state_add(xs, extack);
	err = real_dev->xfrmdev_ops->xdo_dev_state_add(real_dev, xs, extack);
	if (!err) {
		ipsec->xs = xs;
		INIT_LIST_HEAD(&ipsec->list);
@@ -540,7 +541,8 @@ static void bond_ipsec_add_sa_all(struct bonding *bond)
			continue;

		ipsec->xs->xso.real_dev = real_dev;
		if (real_dev->xfrmdev_ops->xdo_dev_state_add(ipsec->xs, NULL)) {
		if (real_dev->xfrmdev_ops->xdo_dev_state_add(real_dev,
							     ipsec->xs, NULL)) {
			slave_warn(bond_dev, real_dev, "%s: failed to add SA\n", __func__);
			ipsec->xs->xso.real_dev = NULL;
		}
@@ -551,11 +553,12 @@ 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
 **/
static void bond_ipsec_del_sa(struct xfrm_state *xs)
static void bond_ipsec_del_sa(struct net_device *bond_dev,
			      struct xfrm_state *xs)
{
	struct net_device *bond_dev = xs->xso.dev;
	struct net_device *real_dev;
	netdevice_tracker tracker;
	struct bond_ipsec *ipsec;
@@ -587,7 +590,7 @@ static void bond_ipsec_del_sa(struct xfrm_state *xs)
		goto out;
	}

	real_dev->xfrmdev_ops->xdo_dev_state_delete(xs);
	real_dev->xfrmdev_ops->xdo_dev_state_delete(real_dev, xs);
out:
	netdev_put(real_dev, &tracker);
	mutex_lock(&bond->ipsec_lock);
@@ -624,18 +627,20 @@ static void bond_ipsec_del_sa_all(struct bonding *bond)
			slave_warn(bond_dev, real_dev,
				   "%s: no slave xdo_dev_state_delete\n",
				   __func__);
		} else {
			real_dev->xfrmdev_ops->xdo_dev_state_delete(ipsec->xs);
			if (real_dev->xfrmdev_ops->xdo_dev_state_free)
				real_dev->xfrmdev_ops->xdo_dev_state_free(ipsec->xs);
			continue;
		}
		real_dev->xfrmdev_ops->xdo_dev_state_delete(real_dev,
							    ipsec->xs);
		if (real_dev->xfrmdev_ops->xdo_dev_state_free)
			real_dev->xfrmdev_ops->xdo_dev_state_free(real_dev,
								  ipsec->xs);
	}
	mutex_unlock(&bond->ipsec_lock);
}

static void bond_ipsec_free_sa(struct xfrm_state *xs)
static void bond_ipsec_free_sa(struct net_device *bond_dev,
			       struct xfrm_state *xs)
{
	struct net_device *bond_dev = xs->xso.dev;
	struct net_device *real_dev;
	netdevice_tracker tracker;
	struct bonding *bond;
@@ -661,7 +666,7 @@ static void bond_ipsec_free_sa(struct xfrm_state *xs)

	if (real_dev && real_dev->xfrmdev_ops &&
	    real_dev->xfrmdev_ops->xdo_dev_state_free)
		real_dev->xfrmdev_ops->xdo_dev_state_free(xs);
		real_dev->xfrmdev_ops->xdo_dev_state_free(real_dev, xs);
out:
	netdev_put(real_dev, &tracker);
}
+11 −9
Original line number Diff line number Diff line
@@ -6480,10 +6480,11 @@ static const struct tlsdev_ops cxgb4_ktls_ops = {

#if IS_ENABLED(CONFIG_CHELSIO_IPSEC_INLINE)

static int cxgb4_xfrm_add_state(struct xfrm_state *x,
static int cxgb4_xfrm_add_state(struct net_device *dev,
				struct xfrm_state *x,
				struct netlink_ext_ack *extack)
{
	struct adapter *adap = netdev2adap(x->xso.dev);
	struct adapter *adap = netdev2adap(dev);
	int ret;

	if (!mutex_trylock(&uld_mutex)) {
@@ -6494,7 +6495,8 @@ static int cxgb4_xfrm_add_state(struct xfrm_state *x,
	if (ret)
		goto out_unlock;

	ret = adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_state_add(x, extack);
	ret = adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_state_add(dev, x,
									extack);

out_unlock:
	mutex_unlock(&uld_mutex);
@@ -6502,9 +6504,9 @@ static int cxgb4_xfrm_add_state(struct xfrm_state *x,
	return ret;
}

static void cxgb4_xfrm_del_state(struct xfrm_state *x)
static void cxgb4_xfrm_del_state(struct net_device *dev, struct xfrm_state *x)
{
	struct adapter *adap = netdev2adap(x->xso.dev);
	struct adapter *adap = netdev2adap(dev);

	if (!mutex_trylock(&uld_mutex)) {
		dev_dbg(adap->pdev_dev,
@@ -6514,15 +6516,15 @@ static void cxgb4_xfrm_del_state(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(x);
	adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_state_delete(dev, x);

out_unlock:
	mutex_unlock(&uld_mutex);
}

static void cxgb4_xfrm_free_state(struct xfrm_state *x)
static void cxgb4_xfrm_free_state(struct net_device *dev, struct xfrm_state *x)
{
	struct adapter *adap = netdev2adap(x->xso.dev);
	struct adapter *adap = netdev2adap(dev);

	if (!mutex_trylock(&uld_mutex)) {
		dev_dbg(adap->pdev_dev,
@@ -6532,7 +6534,7 @@ static void cxgb4_xfrm_free_state(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(x);
	adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_state_free(dev, x);

out_unlock:
	mutex_unlock(&uld_mutex);
+12 −6
Original line number Diff line number Diff line
@@ -75,9 +75,12 @@ static int ch_ipsec_uld_state_change(void *handle, enum cxgb4_state new_state);
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 xfrm_state *x);
static void ch_ipsec_xfrm_del_state(struct xfrm_state *x);
static int ch_ipsec_xfrm_add_state(struct xfrm_state *x,
static void ch_ipsec_xfrm_free_state(struct net_device *dev,
				     struct xfrm_state *x);
static void ch_ipsec_xfrm_del_state(struct net_device *dev,
				    struct xfrm_state *x);
static int ch_ipsec_xfrm_add_state(struct net_device *dev,
				   struct xfrm_state *x,
				   struct netlink_ext_ack *extack);

static const struct xfrmdev_ops ch_ipsec_xfrmdev_ops = {
@@ -223,7 +226,8 @@ static int ch_ipsec_setkey(struct xfrm_state *x,
 * returns 0 on success, negative error if failed to send message to FPGA
 * positive error if FPGA returned a bad response
 */
static int ch_ipsec_xfrm_add_state(struct xfrm_state *x,
static int ch_ipsec_xfrm_add_state(struct net_device *dev,
				   struct xfrm_state *x,
				   struct netlink_ext_ack *extack)
{
	struct ipsec_sa_entry *sa_entry;
@@ -302,14 +306,16 @@ static int ch_ipsec_xfrm_add_state(struct xfrm_state *x,
	return res;
}

static void ch_ipsec_xfrm_del_state(struct xfrm_state *x)
static void ch_ipsec_xfrm_del_state(struct net_device *dev,
				    struct xfrm_state *x)
{
	/* do nothing */
	if (!x->xso.offload_handle)
		return;
}

static void ch_ipsec_xfrm_free_state(struct xfrm_state *x)
static void ch_ipsec_xfrm_free_state(struct net_device *dev,
				     struct xfrm_state *x)
{
	struct ipsec_sa_entry *sa_entry;

+23 −18
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@
#define IXGBE_IPSEC_KEY_BITS  160
static const char aes_gcm_name[] = "rfc4106(gcm(aes))";

static void ixgbe_ipsec_del_sa(struct xfrm_state *xs);
static void ixgbe_ipsec_del_sa(struct net_device *dev, struct xfrm_state *xs);

/**
 * ixgbe_ipsec_set_tx_sa - set the Tx SA registers
@@ -321,7 +321,7 @@ void ixgbe_ipsec_restore(struct ixgbe_adapter *adapter)

		if (r->used) {
			if (r->mode & IXGBE_RXTXMOD_VF)
				ixgbe_ipsec_del_sa(r->xs);
				ixgbe_ipsec_del_sa(adapter->netdev, r->xs);
			else
				ixgbe_ipsec_set_rx_sa(hw, i, r->xs->id.spi,
						      r->key, r->salt,
@@ -330,7 +330,7 @@ void ixgbe_ipsec_restore(struct ixgbe_adapter *adapter)

		if (t->used) {
			if (t->mode & IXGBE_RXTXMOD_VF)
				ixgbe_ipsec_del_sa(t->xs);
				ixgbe_ipsec_del_sa(adapter->netdev, t->xs);
			else
				ixgbe_ipsec_set_tx_sa(hw, i, t->key, t->salt);
		}
@@ -417,6 +417,7 @@ static struct xfrm_state *ixgbe_ipsec_find_rx_state(struct ixgbe_ipsec *ipsec,

/**
 * ixgbe_ipsec_parse_proto_keys - find the key and salt based on the protocol
 * @dev: pointer to net device
 * @xs: pointer to xfrm_state struct
 * @mykey: pointer to key array to populate
 * @mysalt: pointer to salt value to populate
@@ -424,10 +425,10 @@ static struct xfrm_state *ixgbe_ipsec_find_rx_state(struct ixgbe_ipsec *ipsec,
 * This copies the protocol keys and salt to our own data tables.  The
 * 82599 family only supports the one algorithm.
 **/
static int ixgbe_ipsec_parse_proto_keys(struct xfrm_state *xs,
static int ixgbe_ipsec_parse_proto_keys(struct net_device *dev,
					struct xfrm_state *xs,
					u32 *mykey, u32 *mysalt)
{
	struct net_device *dev = xs->xso.real_dev;
	unsigned char *key_data;
	char *alg_name = NULL;
	int key_len;
@@ -473,11 +474,12 @@ static int ixgbe_ipsec_parse_proto_keys(struct xfrm_state *xs,

/**
 * ixgbe_ipsec_check_mgmt_ip - make sure there is no clash with mgmt IP filters
 * @dev: pointer to net device
 * @xs: pointer to transformer state struct
 **/
static int ixgbe_ipsec_check_mgmt_ip(struct xfrm_state *xs)
static int ixgbe_ipsec_check_mgmt_ip(struct net_device *dev,
				     struct xfrm_state *xs)
{
	struct net_device *dev = xs->xso.real_dev;
	struct ixgbe_adapter *adapter = netdev_priv(dev);
	struct ixgbe_hw *hw = &adapter->hw;
	u32 mfval, manc, reg;
@@ -556,13 +558,14 @@ static int ixgbe_ipsec_check_mgmt_ip(struct xfrm_state *xs)

/**
 * ixgbe_ipsec_add_sa - program device with a security association
 * @dev: pointer to device to program
 * @xs: pointer to transformer state struct
 * @extack: extack point to fill failure reason
 **/
static int ixgbe_ipsec_add_sa(struct xfrm_state *xs,
static int ixgbe_ipsec_add_sa(struct net_device *dev,
			      struct xfrm_state *xs,
			      struct netlink_ext_ack *extack)
{
	struct net_device *dev = xs->xso.real_dev;
	struct ixgbe_adapter *adapter = netdev_priv(dev);
	struct ixgbe_ipsec *ipsec = adapter->ipsec;
	struct ixgbe_hw *hw = &adapter->hw;
@@ -581,7 +584,7 @@ static int ixgbe_ipsec_add_sa(struct xfrm_state *xs,
		return -EINVAL;
	}

	if (ixgbe_ipsec_check_mgmt_ip(xs)) {
	if (ixgbe_ipsec_check_mgmt_ip(dev, xs)) {
		NL_SET_ERR_MSG_MOD(extack, "IPsec IP addr clash with mgmt filters");
		return -EINVAL;
	}
@@ -615,7 +618,7 @@ static int ixgbe_ipsec_add_sa(struct xfrm_state *xs,
			rsa.decrypt = xs->ealg || xs->aead;

		/* get the key and salt */
		ret = ixgbe_ipsec_parse_proto_keys(xs, rsa.key, &rsa.salt);
		ret = ixgbe_ipsec_parse_proto_keys(dev, xs, rsa.key, &rsa.salt);
		if (ret) {
			NL_SET_ERR_MSG_MOD(extack, "Failed to get key data for Rx SA table");
			return ret;
@@ -724,7 +727,7 @@ static int ixgbe_ipsec_add_sa(struct xfrm_state *xs,
		if (xs->id.proto & IPPROTO_ESP)
			tsa.encrypt = xs->ealg || xs->aead;

		ret = ixgbe_ipsec_parse_proto_keys(xs, tsa.key, &tsa.salt);
		ret = ixgbe_ipsec_parse_proto_keys(dev, xs, tsa.key, &tsa.salt);
		if (ret) {
			NL_SET_ERR_MSG_MOD(extack, "Failed to get key data for Tx SA table");
			memset(&tsa, 0, sizeof(tsa));
@@ -752,11 +755,11 @@ static int ixgbe_ipsec_add_sa(struct xfrm_state *xs,

/**
 * ixgbe_ipsec_del_sa - clear out this specific SA
 * @dev: pointer to device to program
 * @xs: pointer to transformer state struct
 **/
static void ixgbe_ipsec_del_sa(struct xfrm_state *xs)
static void ixgbe_ipsec_del_sa(struct net_device *dev, struct xfrm_state *xs)
{
	struct net_device *dev = xs->xso.real_dev;
	struct ixgbe_adapter *adapter = netdev_priv(dev);
	struct ixgbe_ipsec *ipsec = adapter->ipsec;
	struct ixgbe_hw *hw = &adapter->hw;
@@ -841,7 +844,8 @@ void ixgbe_ipsec_vf_clear(struct ixgbe_adapter *adapter, u32 vf)
			continue;
		if (ipsec->rx_tbl[i].mode & IXGBE_RXTXMOD_VF &&
		    ipsec->rx_tbl[i].vf == vf)
			ixgbe_ipsec_del_sa(ipsec->rx_tbl[i].xs);
			ixgbe_ipsec_del_sa(adapter->netdev,
					   ipsec->rx_tbl[i].xs);
	}

	/* search tx sa table */
@@ -850,7 +854,8 @@ void ixgbe_ipsec_vf_clear(struct ixgbe_adapter *adapter, u32 vf)
			continue;
		if (ipsec->tx_tbl[i].mode & IXGBE_RXTXMOD_VF &&
		    ipsec->tx_tbl[i].vf == vf)
			ixgbe_ipsec_del_sa(ipsec->tx_tbl[i].xs);
			ixgbe_ipsec_del_sa(adapter->netdev,
					   ipsec->tx_tbl[i].xs);
	}
}

@@ -930,7 +935,7 @@ 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(xs, NULL);
	err = ixgbe_ipsec_add_sa(adapter->netdev, xs, NULL);
	if (err)
		goto err_aead;

@@ -1034,7 +1039,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(xs);
	ixgbe_ipsec_del_sa(adapter->netdev, xs);

	/* remove the xs that was made-up in the add request */
	kfree_sensitive(xs);
Loading