diff options
Diffstat (limited to 'drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c')
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 79 | 
1 files changed, 75 insertions, 4 deletions
| diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 23b7e8d6386b..eeccd586e781 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -98,6 +98,10 @@ struct mlxsw_sp_bridge_ops {  		       const struct mlxsw_sp_fid *fid);  }; +struct mlxsw_sp_switchdev_ops { +	void (*init)(struct mlxsw_sp *mlxsw_sp); +}; +  static int  mlxsw_sp_bridge_port_fdb_flush(struct mlxsw_sp *mlxsw_sp,  			       struct mlxsw_sp_bridge_port *bridge_port, @@ -2296,7 +2300,7 @@ mlxsw_sp_bridge_8021ad_vxlan_join(struct mlxsw_sp_bridge_device *bridge_device,  						     vid, ETH_P_8021AD, extack);  } -static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021ad_ops = { +static const struct mlxsw_sp_bridge_ops mlxsw_sp1_bridge_8021ad_ops = {  	.port_join	= mlxsw_sp_bridge_8021ad_port_join,  	.port_leave	= mlxsw_sp_bridge_8021ad_port_leave,  	.vxlan_join	= mlxsw_sp_bridge_8021ad_vxlan_join, @@ -2305,6 +2309,53 @@ static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021ad_ops = {  	.fid_vid	= mlxsw_sp_bridge_8021q_fid_vid,  }; +static int +mlxsw_sp2_bridge_8021ad_port_join(struct mlxsw_sp_bridge_device *bridge_device, +				  struct mlxsw_sp_bridge_port *bridge_port, +				  struct mlxsw_sp_port *mlxsw_sp_port, +				  struct netlink_ext_ack *extack) +{ +	int err; + +	/* The EtherType of decapsulated packets is determined at the egress +	 * port to allow 802.1d and 802.1ad bridges with VXLAN devices to +	 * co-exist. +	 */ +	err = mlxsw_sp_port_egress_ethtype_set(mlxsw_sp_port, ETH_P_8021AD); +	if (err) +		return err; + +	err = mlxsw_sp_bridge_8021ad_port_join(bridge_device, bridge_port, +					       mlxsw_sp_port, extack); +	if (err) +		goto err_bridge_8021ad_port_join; + +	return 0; + +err_bridge_8021ad_port_join: +	mlxsw_sp_port_egress_ethtype_set(mlxsw_sp_port, ETH_P_8021Q); +	return err; +} + +static void +mlxsw_sp2_bridge_8021ad_port_leave(struct mlxsw_sp_bridge_device *bridge_device, +				   struct mlxsw_sp_bridge_port *bridge_port, +				   struct mlxsw_sp_port *mlxsw_sp_port) +{ +	mlxsw_sp_bridge_8021ad_port_leave(bridge_device, bridge_port, +					  mlxsw_sp_port); +	mlxsw_sp_port_egress_ethtype_set(mlxsw_sp_port, ETH_P_8021Q); +} + +static const struct mlxsw_sp_bridge_ops mlxsw_sp2_bridge_8021ad_ops = { +	.port_join	= mlxsw_sp2_bridge_8021ad_port_join, +	.port_leave	= mlxsw_sp2_bridge_8021ad_port_leave, +	.vxlan_join	= mlxsw_sp_bridge_8021ad_vxlan_join, +	.fid_get	= mlxsw_sp_bridge_8021q_fid_get, +	.fid_lookup	= mlxsw_sp_bridge_8021q_fid_lookup, +	.fid_vid	= mlxsw_sp_bridge_8021q_fid_vid, +}; +  int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port,  			      struct net_device *brport_dev,  			      struct net_device *br_dev, @@ -2865,7 +2916,8 @@ mlxsw_sp_switchdev_bridge_nve_fdb_event(struct mlxsw_sp_switchdev_event_work *  		return;  	if (switchdev_work->event == SWITCHDEV_FDB_ADD_TO_DEVICE && -	    !switchdev_work->fdb_info.added_by_user) +	    (!switchdev_work->fdb_info.added_by_user || +	     switchdev_work->fdb_info.is_local))  		return;  	if (!netif_running(dev)) @@ -2920,7 +2972,7 @@ static void mlxsw_sp_switchdev_bridge_fdb_event_work(struct work_struct *work)  	switch (switchdev_work->event) {  	case SWITCHDEV_FDB_ADD_TO_DEVICE:  		fdb_info = &switchdev_work->fdb_info; -		if (!fdb_info->added_by_user) +		if (!fdb_info->added_by_user || fdb_info->is_local)  			break;  		err = mlxsw_sp_port_fdb_set(mlxsw_sp_port, fdb_info, true);  		if (err) @@ -3535,6 +3587,24 @@ static void mlxsw_sp_fdb_fini(struct mlxsw_sp *mlxsw_sp)  	unregister_switchdev_notifier(&mlxsw_sp_switchdev_notifier);  } +static void mlxsw_sp1_switchdev_init(struct mlxsw_sp *mlxsw_sp) +{ +	mlxsw_sp->bridge->bridge_8021ad_ops = &mlxsw_sp1_bridge_8021ad_ops; +} + +const struct mlxsw_sp_switchdev_ops mlxsw_sp1_switchdev_ops = { +	.init	= mlxsw_sp1_switchdev_init, +}; + +static void mlxsw_sp2_switchdev_init(struct mlxsw_sp *mlxsw_sp) +{ +	mlxsw_sp->bridge->bridge_8021ad_ops = &mlxsw_sp2_bridge_8021ad_ops; +} + +const struct mlxsw_sp_switchdev_ops mlxsw_sp2_switchdev_ops = { +	.init	= mlxsw_sp2_switchdev_init, +}; +  int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp)  {  	struct mlxsw_sp_bridge *bridge; @@ -3549,7 +3619,8 @@ int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp)  	bridge->bridge_8021q_ops = &mlxsw_sp_bridge_8021q_ops;  	bridge->bridge_8021d_ops = &mlxsw_sp_bridge_8021d_ops; -	bridge->bridge_8021ad_ops = &mlxsw_sp_bridge_8021ad_ops; + +	mlxsw_sp->switchdev_ops->init(mlxsw_sp);  	return mlxsw_sp_fdb_init(mlxsw_sp);  } | 
