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] [thread-next>] [day] [month] [year] [list]
Date:   Mon, 9 Nov 2020 01:57:02 +0200
From:   Vladimir Oltean <olteanv@...il.com>
To:     Andrew Lunn <andrew@...n.ch>,
        Vivien Didelot <vivien.didelot@...il.com>,
        Florian Fainelli <f.fainelli@...il.com>,
        Jakub Kicinski <kuba@...nel.org>, netdev@...r.kernel.org,
        linux-kernel@...r.kernel.org
Cc:     DENG Qingfang <dqfext@...il.com>,
        Tobias Waldekranz <tobias@...dekranz.com>,
        Marek Behun <marek.behun@....cz>,
        Russell King - ARM Linux admin <linux@...linux.org.uk>
Subject: Re: [RFC PATCH net-next 1/3] net: dsa: don't use
 switchdev_notifier_fdb_info in dsa_switchdev_event_work

On Sun, Nov 08, 2020 at 03:19:51PM +0200, Vladimir Oltean wrote:
> diff --git a/net/dsa/slave.c b/net/dsa/slave.c
> index 59c80052e950..30db8230e30b 100644
> --- a/net/dsa/slave.c
> +++ b/net/dsa/slave.c
> @@ -2062,72 +2062,62 @@ static int dsa_slave_netdevice_event(struct notifier_block *nb,
>  	return NOTIFY_DONE;
>  }
>  
> -struct dsa_switchdev_event_work {
> -	struct work_struct work;
> -	struct switchdev_notifier_fdb_info fdb_info;
> -	struct net_device *dev;
> -	unsigned long event;
> -};
> +static void
> +dsa_fdb_offload_notify(struct dsa_switchdev_event_work *switchdev_work)
> +{
> +	struct dsa_switch *ds = switchdev_work->ds;
> +	struct dsa_port *dp = dsa_to_port(ds, switchdev_work->port);
> +	struct switchdev_notifier_fdb_info info;
> +
> +	if (!dsa_is_user_port(ds, dp->index))
> +		return;
> +
> +	info.addr = switchdev_work->addr;
> +	info.vid = switchdev_work->vid;
> +	info.offloaded = true;
> +	call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED,
> +				 dp->slave, &info.info, NULL);
> +}
>  
>  static void dsa_slave_switchdev_event_work(struct work_struct *work)
>  {
>  	struct dsa_switchdev_event_work *switchdev_work =
>  		container_of(work, struct dsa_switchdev_event_work, work);
> -	struct net_device *dev = switchdev_work->dev;
> -	struct switchdev_notifier_fdb_info *fdb_info;
> -	struct dsa_port *dp = dsa_slave_to_port(dev);
> +	struct dsa_switch *ds = switchdev_work->ds;
> +	struct dsa_port *dp;
>  	int err;
>  
> +	dp = dsa_to_port(ds, switchdev_work->port);
> +
>  	rtnl_lock();
>  	switch (switchdev_work->event) {
>  	case SWITCHDEV_FDB_ADD_TO_DEVICE:
> -		fdb_info = &switchdev_work->fdb_info;
> -		if (!fdb_info->added_by_user)
> -			break;
> -
> -		err = dsa_port_fdb_add(dp, fdb_info->addr, fdb_info->vid);
> +		err = dsa_port_fdb_add(dp, switchdev_work->addr,
> +				       switchdev_work->vid);
>  		if (err) {
> -			netdev_dbg(dev, "fdb add failed err=%d\n", err);
> +			dev_dbg(ds->dev, "port %d fdb add failed err=%d\n",
> +				dp->index, err);
>  			break;
>  		}
> -		fdb_info->offloaded = true;
> -		call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, dev,
> -					 &fdb_info->info, NULL);
> +		dsa_fdb_offload_notify(switchdev_work);
>  		break;
>  
>  	case SWITCHDEV_FDB_DEL_TO_DEVICE:
> -		fdb_info = &switchdev_work->fdb_info;
> -		if (!fdb_info->added_by_user)
> -			break;
> -
> -		err = dsa_port_fdb_del(dp, fdb_info->addr, fdb_info->vid);
> +		err = dsa_port_fdb_del(dp, switchdev_work->addr,
> +				       switchdev_work->vid);
>  		if (err) {
> -			netdev_dbg(dev, "fdb del failed err=%d\n", err);
> -			dev_close(dev);
> +			dev_dbg(ds->dev, "port %d fdb del failed err=%d\n",
> +				dp->index, err);
> +			if (dsa_is_user_port(ds, dp->index))
> +				dev_close(dp->slave);

Not sure that this dev_close() serves any real purpose, it stands in the
way a little. It was introduced "to indicate inconsistent situation".

commit c9eb3e0f870105242a15a5e628ed202cf32afe0d
Author: Arkadi Sharshevsky <arkadis@...lanox.com>
Date:   Sun Aug 6 16:15:42 2017 +0300

    net: dsa: Add support for learning FDB through notification

    Add support for learning FDB through notification. The driver defers
    the hardware update via ordered work queue. In case of a successful
    FDB add a notification is sent back to bridge.

    In case of hw FDB del failure the static FDB will be deleted from
    the bridge, thus, the interface is moved to down state in order to
    indicate inconsistent situation.

I hope it's ok to only close a net device if it exists, I can't think of
anything smarter.

>  		}
>  		break;
>  	}
>  	rtnl_unlock();
>  
> -	kfree(switchdev_work->fdb_info.addr);
>  	kfree(switchdev_work);
> -	dev_put(dev);
> -}
> -
> -static int
> -dsa_slave_switchdev_fdb_work_init(struct dsa_switchdev_event_work *
> -				  switchdev_work,
> -				  const struct switchdev_notifier_fdb_info *
> -				  fdb_info)
> -{
> -	memcpy(&switchdev_work->fdb_info, fdb_info,
> -	       sizeof(switchdev_work->fdb_info));
> -	switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC);
> -	if (!switchdev_work->fdb_info.addr)
> -		return -ENOMEM;
> -	ether_addr_copy((u8 *)switchdev_work->fdb_info.addr,
> -			fdb_info->addr);
> -	return 0;
> +	if (dsa_is_user_port(ds, dp->index))
> +		dev_put(dp->slave);
>  }

The reference counting is broken here. It doesn't line up with the
dev_hold(dev) done in the last patch, which is on a non-DSA interface.
Anyway I think a net_device refcount is way too much for what we need
here, which is to ensure that DSA doesn't get unbound. I think I'll just
simplify to get_device(ds->dev) and put_device(ds->dev).

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ