diff mbox series

[net,V3,1/3] bonding: implement xdo_dev_state_free and call it after deletion

Message ID 20240805050357.2004888-2-tariqt@nvidia.com (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series Fixes for IPsec over bonding | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag present in non-next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 29 this patch: 29
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers fail 1 blamed authors not CCed: ap420073@gmail.com; 1 maintainers not CCed: ap420073@gmail.com
netdev/build_clang success Errors and warnings before: 29 this patch: 29
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success Fixes tag looks correct
netdev/build_allmodconfig_warn success Errors and warnings before: 29 this patch: 29
netdev/checkpatch warning WARNING: line length of 87 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 13 this patch: 13
netdev/source_inline success Was 0 now: 0
netdev/contest success net-next-2024-08-06--00-00 (tests: 707)

Commit Message

Tariq Toukan Aug. 5, 2024, 5:03 a.m. UTC
From: Jianbo Liu <jianbol@nvidia.com>

Add this implementation for bonding, so hardware resources can be
freed after xfrm state is deleted.

And call it when deleting all SAs from old active real interface.

Fixes: 9a5605505d9c ("bonding: Add struct bond_ipesc to manage SA")
Signed-off-by: Jianbo Liu <jianbol@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
 drivers/net/bonding/bond_main.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

Comments

Hangbin Liu Aug. 6, 2024, 8:45 a.m. UTC | #1
On Mon, Aug 05, 2024 at 08:03:55AM +0300, Tariq Toukan wrote:
> From: Jianbo Liu <jianbol@nvidia.com>
> 
> Add this implementation for bonding, so hardware resources can be
> freed after xfrm state is deleted.
> 
> And call it when deleting all SAs from old active real interface.
> 
> Fixes: 9a5605505d9c ("bonding: Add struct bond_ipesc to manage SA")
> Signed-off-by: Jianbo Liu <jianbol@nvidia.com>
> Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
> ---
>  drivers/net/bonding/bond_main.c | 32 ++++++++++++++++++++++++++++++++
>  1 file changed, 32 insertions(+)
> 
> diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
> index 1cd92c12e782..eb5e43860670 100644
> --- a/drivers/net/bonding/bond_main.c
> +++ b/drivers/net/bonding/bond_main.c
> @@ -581,6 +581,8 @@ 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);
>  		}
>  		ipsec->xs->xso.real_dev = NULL;
>  	}
> @@ -588,6 +590,35 @@ static void bond_ipsec_del_sa_all(struct bonding *bond)
>  	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;
> +	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;
> +	rcu_read_unlock();
> +
> +	if (!slave)
> +		return;
> +
> +	if (!xs->xso.real_dev)
> +		return;
> +
> +	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);

Do we need to check netif_is_bond_master(slave->dev) here?

Thanks
Hangbin
Jianbo Liu Aug. 6, 2024, 9:09 a.m. UTC | #2
On Tue, 2024-08-06 at 16:45 +0800, Hangbin Liu wrote:
> On Mon, Aug 05, 2024 at 08:03:55AM +0300, Tariq Toukan wrote:
> > From: Jianbo Liu <jianbol@nvidia.com>
> > 
> > Add this implementation for bonding, so hardware resources can be
> > freed after xfrm state is deleted.
> > 
> > And call it when deleting all SAs from old active real interface.
> > 
> > Fixes: 9a5605505d9c ("bonding: Add struct bond_ipesc to manage SA")
> > Signed-off-by: Jianbo Liu <jianbol@nvidia.com>
> > Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
> > ---
> >  drivers/net/bonding/bond_main.c | 32
> > ++++++++++++++++++++++++++++++++
> >  1 file changed, 32 insertions(+)
> > 
> > diff --git a/drivers/net/bonding/bond_main.c
> > b/drivers/net/bonding/bond_main.c
> > index 1cd92c12e782..eb5e43860670 100644
> > --- a/drivers/net/bonding/bond_main.c
> > +++ b/drivers/net/bonding/bond_main.c
> > @@ -581,6 +581,8 @@ 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);
> >                 }
> >                 ipsec->xs->xso.real_dev = NULL;
> >         }
> > @@ -588,6 +590,35 @@ static void bond_ipsec_del_sa_all(struct
> > bonding *bond)
> >         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;
> > +       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;
> > +       rcu_read_unlock();
> > +
> > +       if (!slave)
> > +               return;
> > +
> > +       if (!xs->xso.real_dev)
> > +               return;
> > +
> > +       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);
> 
> Do we need to check netif_is_bond_master(slave->dev) here?

Probably no need, because we will not call xdo_dev_state_free only. It
is called after xdo_dev_state_delete.

> 
> Thanks
> Hangbin
Hangbin Liu Aug. 7, 2024, 10:11 a.m. UTC | #3
On Mon, Aug 05, 2024 at 08:03:55AM +0300, Tariq Toukan wrote:
> From: Jianbo Liu <jianbol@nvidia.com>
> 
> Add this implementation for bonding, so hardware resources can be
> freed after xfrm state is deleted.
> 
> And call it when deleting all SAs from old active real interface.
> 
> Fixes: 9a5605505d9c ("bonding: Add struct bond_ipesc to manage SA")
> Signed-off-by: Jianbo Liu <jianbol@nvidia.com>
> Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
> ---
>  drivers/net/bonding/bond_main.c | 32 ++++++++++++++++++++++++++++++++
>  1 file changed, 32 insertions(+)
> 
> diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
> index 1cd92c12e782..eb5e43860670 100644
> --- a/drivers/net/bonding/bond_main.c
> +++ b/drivers/net/bonding/bond_main.c
> @@ -581,6 +581,8 @@ 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);
>  		}
>  		ipsec->xs->xso.real_dev = NULL;
>  	}
> @@ -588,6 +590,35 @@ static void bond_ipsec_del_sa_all(struct bonding *bond)
>  	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;
> +	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;
> +	rcu_read_unlock();
> +
> +	if (!slave)
> +		return;
> +
> +	if (!xs->xso.real_dev)
> +		return;
> +
> +	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);
> +}
> +
>  /**
>   * bond_ipsec_offload_ok - can this packet use the xfrm hw offload
>   * @skb: current data packet
> @@ -632,6 +663,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 */
> -- 
> 2.44.0
> 

Reviewed-by: Hangbin Liu <liuhangbin@gmail.com>
Jakub Kicinski Aug. 13, 2024, 12:48 a.m. UTC | #4
On Mon, 5 Aug 2024 08:03:55 +0300 Tariq Toukan wrote:
> +static void bond_ipsec_free_sa(struct xfrm_state *xs)
> +{
> +	struct net_device *bond_dev = xs->xso.dev;
> +	struct net_device *real_dev;
> +	struct bonding *bond;
> +	struct slave *slave;
> +
> +	if (!bond_dev)
> +		return;

can xs->xso.dev be NULL during the dev_free_state callback?

> +	rcu_read_lock();
> +	bond = netdev_priv(bond_dev);
> +	slave = rcu_dereference(bond->curr_active_slave);
> +	real_dev = slave ? slave->dev : NULL;
> +	rcu_read_unlock();

What's holding onto real_dev once you drop the rcu lock here?
Jianbo Liu Aug. 13, 2024, 2:58 a.m. UTC | #5
On Mon, 2024-08-12 at 17:48 -0700, Jakub Kicinski wrote:
> On Mon, 5 Aug 2024 08:03:55 +0300 Tariq Toukan wrote:
> > +static void bond_ipsec_free_sa(struct xfrm_state *xs)
> > +{
> > +       struct net_device *bond_dev = xs->xso.dev;
> > +       struct net_device *real_dev;
> > +       struct bonding *bond;
> > +       struct slave *slave;
> > +
> > +       if (!bond_dev)
> > +               return;
> 
> can xs->xso.dev be NULL during the dev_free_state callback?

Shouldn't be NULL because bond_ipsec_del_sa is called before and xs is
removed from bond->ipsec_list, so xs->xso.dev is kept unless it's
cleared in dev's xdo_dev_state_delete callback.

> 
> > +       rcu_read_lock();
> > +       bond = netdev_priv(bond_dev);
> > +       slave = rcu_dereference(bond->curr_active_slave);
> > +       real_dev = slave ? slave->dev : NULL;
> > +       rcu_read_unlock();
> 
> What's holding onto real_dev once you drop the rcu lock here?

I think it should be xfrm state (and bond device).

Thanks!
Jianbo
Jakub Kicinski Aug. 13, 2024, 2:14 p.m. UTC | #6
On Tue, 13 Aug 2024 02:58:12 +0000 Jianbo Liu wrote:
> > > +       rcu_read_lock();
> > > +       bond = netdev_priv(bond_dev);
> > > +       slave = rcu_dereference(bond->curr_active_slave);
> > > +       real_dev = slave ? slave->dev : NULL;
> > > +       rcu_read_unlock();  
> > 
> > What's holding onto real_dev once you drop the rcu lock here?  
> 
> I think it should be xfrm state (and bond device).

Please explain it in the commit message in more certain terms.
Jianbo Liu Aug. 14, 2024, 2:03 a.m. UTC | #7
On Tue, 2024-08-13 at 07:14 -0700, Jakub Kicinski wrote:
> On Tue, 13 Aug 2024 02:58:12 +0000 Jianbo Liu wrote:
> > > > +       rcu_read_lock();
> > > > +       bond = netdev_priv(bond_dev);
> > > > +       slave = rcu_dereference(bond->curr_active_slave);
> > > > +       real_dev = slave ? slave->dev : NULL;
> > > > +       rcu_read_unlock();  
> > > 
> > > What's holding onto real_dev once you drop the rcu lock here?  
> > 
> > I think it should be xfrm state (and bond device).
> 
> Please explain it in the commit message in more certain terms.

Sorry, I don't understand. The real_dev is saved in xs->xso.real_dev,
and also bond's slave. It's straightforward. What else do I need to
explain?

Thanks!
Jianbo
Hangbin Liu Aug. 14, 2024, 3:11 a.m. UTC | #8
On Wed, Aug 14, 2024 at 02:03:58AM +0000, Jianbo Liu wrote:
> On Tue, 2024-08-13 at 07:14 -0700, Jakub Kicinski wrote:
> > On Tue, 13 Aug 2024 02:58:12 +0000 Jianbo Liu wrote:
> > > > > +       rcu_read_lock();
> > > > > +       bond = netdev_priv(bond_dev);
> > > > > +       slave = rcu_dereference(bond->curr_active_slave);
> > > > > +       real_dev = slave ? slave->dev : NULL;
> > > > > +       rcu_read_unlock();  
> > > > 
> > > > What's holding onto real_dev once you drop the rcu lock here?  
> > > 
> > > I think it should be xfrm state (and bond device).
> > 
> > Please explain it in the commit message in more certain terms.
> 
> Sorry, I don't understand. The real_dev is saved in xs->xso.real_dev,
> and also bond's slave. It's straightforward. What else do I need to
> explain?

I think Jakub means you need to make sure the real_dev is not freed during
xfrmdev_ops. See bond_ipsec_add_sa(). You unlock it too early and later
xfrmdev_ops is not protected.

Hangbin
Jianbo Liu Aug. 15, 2024, 1:23 a.m. UTC | #9
On Wed, 2024-08-14 at 11:11 +0800, Hangbin Liu wrote:
> On Wed, Aug 14, 2024 at 02:03:58AM +0000, Jianbo Liu wrote:
> > On Tue, 2024-08-13 at 07:14 -0700, Jakub Kicinski wrote:
> > > On Tue, 13 Aug 2024 02:58:12 +0000 Jianbo Liu wrote:
> > > > > > +       rcu_read_lock();
> > > > > > +       bond = netdev_priv(bond_dev);
> > > > > > +       slave = rcu_dereference(bond->curr_active_slave);
> > > > > > +       real_dev = slave ? slave->dev : NULL;
> > > > > > +       rcu_read_unlock();  
> > > > > 
> > > > > What's holding onto real_dev once you drop the rcu lock
> > > > > here?  
> > > > 
> > > > I think it should be xfrm state (and bond device).
> > > 
> > > Please explain it in the commit message in more certain terms.
> > 
> > Sorry, I don't understand. The real_dev is saved in xs-
> > >xso.real_dev,
> > and also bond's slave. It's straightforward. What else do I need to
> > explain?
> 
> I think Jakub means you need to make sure the real_dev is not freed
> during
> xfrmdev_ops. See bond_ipsec_add_sa(). You unlock it too early and
> later
> xfrmdev_ops is not protected.

This RCU lock is to protect the reading of curr_active_slave, which is
pointing to a big stuct - slave struct, so there is no error to get
real_dev from slave->dev.

Thanks!
Jianbo
Hangbin Liu Aug. 15, 2024, 3:34 a.m. UTC | #10
On Thu, Aug 15, 2024 at 01:23:05AM +0000, Jianbo Liu wrote:
> On Wed, 2024-08-14 at 11:11 +0800, Hangbin Liu wrote:
> > On Wed, Aug 14, 2024 at 02:03:58AM +0000, Jianbo Liu wrote:
> > > On Tue, 2024-08-13 at 07:14 -0700, Jakub Kicinski wrote:
> > > > On Tue, 13 Aug 2024 02:58:12 +0000 Jianbo Liu wrote:
> > > > > > > +       rcu_read_lock();
> > > > > > > +       bond = netdev_priv(bond_dev);
> > > > > > > +       slave = rcu_dereference(bond->curr_active_slave);
> > > > > > > +       real_dev = slave ? slave->dev : NULL;
> > > > > > > +       rcu_read_unlock();  
> > > > > > 
> > > > > > What's holding onto real_dev once you drop the rcu lock
> > > > > > here?  
> > > > > 
> > > > > I think it should be xfrm state (and bond device).
> > > > 
> > > > Please explain it in the commit message in more certain terms.
> > > 
> > > Sorry, I don't understand. The real_dev is saved in xs-
> > > >xso.real_dev,
> > > and also bond's slave. It's straightforward. What else do I need to
> > > explain?
> > 
> > I think Jakub means you need to make sure the real_dev is not freed
> > during
> > xfrmdev_ops. See bond_ipsec_add_sa(). You unlock it too early and
> > later
> > xfrmdev_ops is not protected.
> 
> This RCU lock is to protect the reading of curr_active_slave, which is
> pointing to a big stuct - slave struct, so there is no error to get
> real_dev from slave->dev.

It's not about getting real_dev from slave->dev. As Jakub said, What's holding
on real_dev once you drop the rcu lock?

Thanks
Hangbin
Jianbo Liu Aug. 15, 2024, 3:57 a.m. UTC | #11
On Thu, 2024-08-15 at 11:34 +0800, Hangbin Liu wrote:
> On Thu, Aug 15, 2024 at 01:23:05AM +0000, Jianbo Liu wrote:
> > On Wed, 2024-08-14 at 11:11 +0800, Hangbin Liu wrote:
> > > On Wed, Aug 14, 2024 at 02:03:58AM +0000, Jianbo Liu wrote:
> > > > On Tue, 2024-08-13 at 07:14 -0700, Jakub Kicinski wrote:
> > > > > On Tue, 13 Aug 2024 02:58:12 +0000 Jianbo Liu wrote:
> > > > > > > > +       rcu_read_lock();
> > > > > > > > +       bond = netdev_priv(bond_dev);
> > > > > > > > +       slave = rcu_dereference(bond-
> > > > > > > > >curr_active_slave);
> > > > > > > > +       real_dev = slave ? slave->dev : NULL;
> > > > > > > > +       rcu_read_unlock();  
> > > > > > > 
> > > > > > > What's holding onto real_dev once you drop the rcu lock
> > > > > > > here?  
> > > > > > 
> > > > > > I think it should be xfrm state (and bond device).
> > > > > 
> > > > > Please explain it in the commit message in more certain
> > > > > terms.
> > > > 
> > > > Sorry, I don't understand. The real_dev is saved in xs-
> > > > > xso.real_dev,
> > > > and also bond's slave. It's straightforward. What else do I
> > > > need to
> > > > explain?
> > > 
> > > I think Jakub means you need to make sure the real_dev is not
> > > freed
> > > during
> > > xfrmdev_ops. See bond_ipsec_add_sa(). You unlock it too early and
> > > later
> > > xfrmdev_ops is not protected.
> > 
> > This RCU lock is to protect the reading of curr_active_slave, which
> > is
> > pointing to a big stuct - slave struct, so there is no error to get
> > real_dev from slave->dev.
> 
> It's not about getting real_dev from slave->dev. As Jakub said,
> What's holding
> on real_dev once you drop the rcu lock?
> 

As you mentioned the lock, I explained what's it used for, so we will
not mix basic concepts and make things complicated. 
As for Jakub's question, I already answered. And I'm waiting for his
reply so I can better undestand how to modify if there is any. 

Thanks!
Jianbo
diff mbox series

Patch

diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 1cd92c12e782..eb5e43860670 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -581,6 +581,8 @@  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);
 		}
 		ipsec->xs->xso.real_dev = NULL;
 	}
@@ -588,6 +590,35 @@  static void bond_ipsec_del_sa_all(struct bonding *bond)
 	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;
+	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;
+	rcu_read_unlock();
+
+	if (!slave)
+		return;
+
+	if (!xs->xso.real_dev)
+		return;
+
+	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);
+}
+
 /**
  * bond_ipsec_offload_ok - can this packet use the xfrm hw offload
  * @skb: current data packet
@@ -632,6 +663,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 */