Commit ec130094 authored by Jianbo Liu's avatar Jianbo Liu Committed by Jakub Kicinski
Browse files

bonding: implement xdo_dev_state_free and call it after deletion



Add this implementation for bonding, so hardware resources can be
freed from the active slave after xfrm state is deleted. The netdev
used to invoke xdo_dev_state_free callback, is saved in the xfrm state
(xs->xso.real_dev), which is also the bond's active slave. To prevent
it from being freed, acquire netdev reference before leaving RCU
read-side critical section, and release it after callback is done.

And call it when deleting all SAs from old active real interface while
switching current active slave.

Fixes: 9a560550 ("bonding: Add struct bond_ipesc to manage SA")
Signed-off-by: default avatarJianbo Liu <jianbol@nvidia.com>
Signed-off-by: default avatarTariq Toukan <tariqt@nvidia.com>
Reviewed-by: default avatarHangbin Liu <liuhangbin@gmail.com>
Acked-by: default avatarJay Vosburgh <jv@jvosburgh.net>
Link: https://patch.msgid.link/20240823031056.110999-2-jianbol@nvidia.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 65a3cce4
Loading
Loading
Loading
Loading
+36 −0
Original line number Diff line number Diff line
@@ -581,12 +581,47 @@ static void bond_ipsec_del_sa_all(struct bonding *bond)
				   __func__);
		} else {
			slave->dev->xfrmdev_ops->xdo_dev_state_delete(ipsec->xs);
			if (slave->dev->xfrmdev_ops->xdo_dev_state_free)
				slave->dev->xfrmdev_ops->xdo_dev_state_free(ipsec->xs);
		}
	}
	spin_unlock_bh(&bond->ipsec_lock);
	rcu_read_unlock();
}

static void bond_ipsec_free_sa(struct xfrm_state *xs)
{
	struct net_device *bond_dev = xs->xso.dev;
	struct net_device *real_dev;
	netdevice_tracker tracker;
	struct bonding *bond;
	struct slave *slave;

	if (!bond_dev)
		return;

	rcu_read_lock();
	bond = netdev_priv(bond_dev);
	slave = rcu_dereference(bond->curr_active_slave);
	real_dev = slave ? slave->dev : NULL;
	netdev_hold(real_dev, &tracker, GFP_ATOMIC);
	rcu_read_unlock();

	if (!slave)
		goto out;

	if (!xs->xso.real_dev)
		goto out;

	WARN_ON(xs->xso.real_dev != real_dev);

	if (real_dev && real_dev->xfrmdev_ops &&
	    real_dev->xfrmdev_ops->xdo_dev_state_free)
		real_dev->xfrmdev_ops->xdo_dev_state_free(xs);
out:
	netdev_put(real_dev, &tracker);
}

/**
 * bond_ipsec_offload_ok - can this packet use the xfrm hw offload
 * @skb: current data packet
@@ -627,6 +662,7 @@ static bool bond_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *xs)
static const struct xfrmdev_ops bond_xfrmdev_ops = {
	.xdo_dev_state_add = bond_ipsec_add_sa,
	.xdo_dev_state_delete = bond_ipsec_del_sa,
	.xdo_dev_state_free = bond_ipsec_free_sa,
	.xdo_dev_offload_ok = bond_ipsec_offload_ok,
};
#endif /* CONFIG_XFRM_OFFLOAD */