 eb964298b3
			
		
	
	eb964298b3
	
	
	
		
			
			Straightforward refresh of patches using update_kernel. Run tested: x86_64 (apu2) Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
		
			
				
	
	
		
			227 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			227 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From c4bb76a9a0ef87c4cc1f636defed5f12deb9f5a7 Mon Sep 17 00:00:00 2001
 | |
| From: Vladimir Oltean <vladimir.oltean@nxp.com>
 | |
| Date: Wed, 6 Jan 2021 11:51:32 +0200
 | |
| Subject: [PATCH] net: dsa: don't use switchdev_notifier_fdb_info in
 | |
|  dsa_switchdev_event_work
 | |
| 
 | |
| Currently DSA doesn't add FDB entries on the CPU port, because it only
 | |
| does so through switchdev, which is associated with a net_device, and
 | |
| there are none of those for the CPU port.
 | |
| 
 | |
| But actually FDB addresses on the CPU port have some use cases of their
 | |
| own, if the switchdev operations are initiated from within the DSA
 | |
| layer. There is just one problem with the existing code: it passes a
 | |
| structure in dsa_switchdev_event_work which was retrieved directly from
 | |
| switchdev, so it contains a net_device. We need to generalize the
 | |
| contents to something that covers the CPU port as well: the "ds, port"
 | |
| tuple is fine for that.
 | |
| 
 | |
| Note that the new procedure for notifying the successful FDB offload is
 | |
| inspired from the rocker model.
 | |
| 
 | |
| Also, nothing was being done if added_by_user was false. Let's check for
 | |
| that a lot earlier, and don't actually bother to schedule the worker
 | |
| for nothing.
 | |
| 
 | |
| Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
 | |
| Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
 | |
| Signed-off-by: Jakub Kicinski <kuba@kernel.org>
 | |
| ---
 | |
|  net/dsa/dsa_priv.h |  12 +++++
 | |
|  net/dsa/slave.c    | 106 ++++++++++++++++++++++-----------------------
 | |
|  2 files changed, 65 insertions(+), 53 deletions(-)
 | |
| 
 | |
| --- a/net/dsa/dsa_priv.h
 | |
| +++ b/net/dsa/dsa_priv.h
 | |
| @@ -73,6 +73,18 @@ struct dsa_notifier_mtu_info {
 | |
|  	int mtu;
 | |
|  };
 | |
|  
 | |
| +struct dsa_switchdev_event_work {
 | |
| +	struct dsa_switch *ds;
 | |
| +	int port;
 | |
| +	struct work_struct work;
 | |
| +	unsigned long event;
 | |
| +	/* Specific for SWITCHDEV_FDB_ADD_TO_DEVICE and
 | |
| +	 * SWITCHDEV_FDB_DEL_TO_DEVICE
 | |
| +	 */
 | |
| +	unsigned char addr[ETH_ALEN];
 | |
| +	u16 vid;
 | |
| +};
 | |
| +
 | |
|  struct dsa_slave_priv {
 | |
|  	/* Copy of CPU port xmit for faster access in slave transmit hot path */
 | |
|  	struct sk_buff *	(*xmit)(struct sk_buff *skb,
 | |
| --- a/net/dsa/slave.c
 | |
| +++ b/net/dsa/slave.c
 | |
| @@ -2050,76 +2050,66 @@ static int dsa_slave_netdevice_event(str
 | |
|  	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 switchdev_notifier_fdb_info info;
 | |
| +	struct dsa_port *dp;
 | |
| +
 | |
| +	if (!dsa_is_user_port(ds, switchdev_work->port))
 | |
| +		return;
 | |
| +
 | |
| +	info.addr = switchdev_work->addr;
 | |
| +	info.vid = switchdev_work->vid;
 | |
| +	info.offloaded = true;
 | |
| +	dp = dsa_to_port(ds, switchdev_work->port);
 | |
| +	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_err(dev,
 | |
| -				   "failed to add %pM vid %d to fdb: %d\n",
 | |
| -				   fdb_info->addr, fdb_info->vid, err);
 | |
| +			dev_err(ds->dev,
 | |
| +				"port %d failed to add %pM vid %d to fdb: %d\n",
 | |
| +				dp->index, switchdev_work->addr,
 | |
| +				switchdev_work->vid, 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_err(dev,
 | |
| -				   "failed to delete %pM vid %d from fdb: %d\n",
 | |
| -				   fdb_info->addr, fdb_info->vid, err);
 | |
| +			dev_err(ds->dev,
 | |
| +				"port %d failed to delete %pM vid %d from fdb: %d\n",
 | |
| +				dp->index, switchdev_work->addr,
 | |
| +				switchdev_work->vid, err);
 | |
|  		}
 | |
|  
 | |
|  		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);
 | |
|  }
 | |
|  
 | |
|  /* Called under rcu_read_lock() */
 | |
| @@ -2127,7 +2117,9 @@ static int dsa_slave_switchdev_event(str
 | |
|  				     unsigned long event, void *ptr)
 | |
|  {
 | |
|  	struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
 | |
| +	const struct switchdev_notifier_fdb_info *fdb_info;
 | |
|  	struct dsa_switchdev_event_work *switchdev_work;
 | |
| +	struct dsa_port *dp;
 | |
|  	int err;
 | |
|  
 | |
|  	if (event == SWITCHDEV_PORT_ATTR_SET) {
 | |
| @@ -2140,20 +2132,32 @@ static int dsa_slave_switchdev_event(str
 | |
|  	if (!dsa_slave_dev_check(dev))
 | |
|  		return NOTIFY_DONE;
 | |
|  
 | |
| +	dp = dsa_slave_to_port(dev);
 | |
| +
 | |
|  	switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC);
 | |
|  	if (!switchdev_work)
 | |
|  		return NOTIFY_BAD;
 | |
|  
 | |
|  	INIT_WORK(&switchdev_work->work,
 | |
|  		  dsa_slave_switchdev_event_work);
 | |
| -	switchdev_work->dev = dev;
 | |
| +	switchdev_work->ds = dp->ds;
 | |
| +	switchdev_work->port = dp->index;
 | |
|  	switchdev_work->event = event;
 | |
|  
 | |
|  	switch (event) {
 | |
|  	case SWITCHDEV_FDB_ADD_TO_DEVICE:
 | |
|  	case SWITCHDEV_FDB_DEL_TO_DEVICE:
 | |
| -		if (dsa_slave_switchdev_fdb_work_init(switchdev_work, ptr))
 | |
| -			goto err_fdb_work_init;
 | |
| +		fdb_info = ptr;
 | |
| +
 | |
| +		if (!fdb_info->added_by_user) {
 | |
| +			kfree(switchdev_work);
 | |
| +			return NOTIFY_OK;
 | |
| +		}
 | |
| +
 | |
| +		ether_addr_copy(switchdev_work->addr,
 | |
| +				fdb_info->addr);
 | |
| +		switchdev_work->vid = fdb_info->vid;
 | |
| +
 | |
|  		dev_hold(dev);
 | |
|  		break;
 | |
|  	default:
 | |
| @@ -2163,10 +2167,6 @@ static int dsa_slave_switchdev_event(str
 | |
|  
 | |
|  	dsa_schedule_work(&switchdev_work->work);
 | |
|  	return NOTIFY_OK;
 | |
| -
 | |
| -err_fdb_work_init:
 | |
| -	kfree(switchdev_work);
 | |
| -	return NOTIFY_BAD;
 | |
|  }
 | |
|  
 | |
|  static int dsa_slave_switchdev_blocking_event(struct notifier_block *unused,
 |