diff options
Diffstat (limited to 'drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c')
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 64 | 
1 files changed, 53 insertions, 11 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 1290b2d3eae6..d88e62bc759f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -782,10 +782,25 @@ err_port_bridge_vlan_learning_set:  static int  mlxsw_sp_port_attr_br_pre_flags_set(struct mlxsw_sp_port *mlxsw_sp_port, -				    struct switchdev_brport_flags flags) +				    const struct net_device *orig_dev, +				    struct switchdev_brport_flags flags, +				    struct netlink_ext_ack *extack)  { -	if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD)) +	if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | +			   BR_PORT_LOCKED | BR_PORT_MAB)) { +		NL_SET_ERR_MSG_MOD(extack, "Unsupported bridge port flag");  		return -EINVAL; +	} + +	if ((flags.mask & BR_PORT_LOCKED) && is_vlan_dev(orig_dev)) { +		NL_SET_ERR_MSG_MOD(extack, "Locked flag cannot be set on a VLAN upper"); +		return -EINVAL; +	} + +	if ((flags.mask & BR_PORT_LOCKED) && vlan_uses_dev(orig_dev)) { +		NL_SET_ERR_MSG_MOD(extack, "Locked flag cannot be set on a bridge port that has VLAN uppers"); +		return -EINVAL; +	}  	return 0;  } @@ -819,6 +834,13 @@ static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port,  			return err;  	} +	if (flags.mask & BR_PORT_LOCKED) { +		err = mlxsw_sp_port_security_set(mlxsw_sp_port, +						 flags.val & BR_PORT_LOCKED); +		if (err) +			return err; +	} +  	if (bridge_port->bridge_device->multicast_enabled)  		goto out; @@ -1186,7 +1208,9 @@ static int mlxsw_sp_port_attr_set(struct net_device *dev, const void *ctx,  		break;  	case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS:  		err = mlxsw_sp_port_attr_br_pre_flags_set(mlxsw_sp_port, -							  attr->u.brport_flags); +							  attr->orig_dev, +							  attr->u.brport_flags, +							  extack);  		break;  	case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:  		err = mlxsw_sp_port_attr_br_flags_set(mlxsw_sp_port, @@ -2783,6 +2807,7 @@ void mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port,  	bridge_device->ops->port_leave(bridge_device, bridge_port,  				       mlxsw_sp_port); +	mlxsw_sp_port_security_set(mlxsw_sp_port, false);  	mlxsw_sp_bridge_port_put(mlxsw_sp->bridge, bridge_port);  } @@ -2888,13 +2913,14 @@ static void mlxsw_sp_fdb_nve_call_notifiers(struct net_device *dev,  static void  mlxsw_sp_fdb_call_notifiers(enum switchdev_notifier_type type,  			    const char *mac, u16 vid, -			    struct net_device *dev, bool offloaded) +			    struct net_device *dev, bool offloaded, bool locked)  {  	struct switchdev_notifier_fdb_info info = {};  	info.addr = mac;  	info.vid = vid;  	info.offloaded = offloaded; +	info.locked = locked;  	call_switchdev_notifiers(type, dev, &info.info, NULL);  } @@ -2941,6 +2967,12 @@ static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp,  	vid = bridge_device->vlan_enabled ? mlxsw_sp_port_vlan->vid : 0;  	evid = mlxsw_sp_port_vlan->vid; +	if (adding && mlxsw_sp_port->security) { +		mlxsw_sp_fdb_call_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE, mac, +					    vid, bridge_port->dev, false, true); +		return; +	} +  do_fdb_op:  	err = mlxsw_sp_port_fdb_uc_op(mlxsw_sp, local_port, mac, fid, evid,  				      adding, true); @@ -2952,7 +2984,8 @@ do_fdb_op:  	if (!do_notification)  		return;  	type = adding ? SWITCHDEV_FDB_ADD_TO_BRIDGE : SWITCHDEV_FDB_DEL_TO_BRIDGE; -	mlxsw_sp_fdb_call_notifiers(type, mac, vid, bridge_port->dev, adding); +	mlxsw_sp_fdb_call_notifiers(type, mac, vid, bridge_port->dev, adding, +				    false);  	return; @@ -3004,6 +3037,12 @@ static void mlxsw_sp_fdb_notify_mac_lag_process(struct mlxsw_sp *mlxsw_sp,  	vid = bridge_device->vlan_enabled ? mlxsw_sp_port_vlan->vid : 0;  	lag_vid = mlxsw_sp_port_vlan->vid; +	if (adding && mlxsw_sp_port->security) { +		mlxsw_sp_fdb_call_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE, mac, +					    vid, bridge_port->dev, false, true); +		return; +	} +  do_fdb_op:  	err = mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp, lag_id, mac, fid, lag_vid,  					  adding, true); @@ -3015,7 +3054,8 @@ do_fdb_op:  	if (!do_notification)  		return;  	type = adding ? SWITCHDEV_FDB_ADD_TO_BRIDGE : SWITCHDEV_FDB_DEL_TO_BRIDGE; -	mlxsw_sp_fdb_call_notifiers(type, mac, vid, bridge_port->dev, adding); +	mlxsw_sp_fdb_call_notifiers(type, mac, vid, bridge_port->dev, adding, +				    false);  	return; @@ -3122,7 +3162,7 @@ static void mlxsw_sp_fdb_notify_mac_uc_tunnel_process(struct mlxsw_sp *mlxsw_sp,  	type = adding ? SWITCHDEV_FDB_ADD_TO_BRIDGE :  			SWITCHDEV_FDB_DEL_TO_BRIDGE; -	mlxsw_sp_fdb_call_notifiers(type, mac, vid, nve_dev, adding); +	mlxsw_sp_fdb_call_notifiers(type, mac, vid, nve_dev, adding, false);  	mlxsw_sp_fid_put(fid); @@ -3264,7 +3304,7 @@ mlxsw_sp_switchdev_bridge_vxlan_fdb_event(struct mlxsw_sp *mlxsw_sp,  					 &vxlan_fdb_info.info, NULL);  		mlxsw_sp_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED,  					    vxlan_fdb_info.eth_addr, -					    fdb_info->vid, dev, true); +					    fdb_info->vid, dev, true, false);  		break;  	case SWITCHDEV_FDB_DEL_TO_DEVICE:  		err = mlxsw_sp_port_fdb_tunnel_uc_op(mlxsw_sp, @@ -3359,7 +3399,7 @@ static void mlxsw_sp_switchdev_bridge_fdb_event_work(struct work_struct *work)  			break;  		mlxsw_sp_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED,  					    fdb_info->addr, -					    fdb_info->vid, dev, true); +					    fdb_info->vid, dev, true, false);  		break;  	case SWITCHDEV_FDB_DEL_TO_DEVICE:  		fdb_info = &switchdev_work->fdb_info; @@ -3443,7 +3483,8 @@ mlxsw_sp_switchdev_vxlan_fdb_add(struct mlxsw_sp *mlxsw_sp,  	call_switchdev_notifiers(SWITCHDEV_VXLAN_FDB_OFFLOADED, dev,  				 &vxlan_fdb_info->info, NULL);  	mlxsw_sp_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED, -				    vxlan_fdb_info->eth_addr, vid, dev, true); +				    vxlan_fdb_info->eth_addr, vid, dev, true, +				    false);  	mlxsw_sp_fid_put(fid); @@ -3495,7 +3536,8 @@ mlxsw_sp_switchdev_vxlan_fdb_del(struct mlxsw_sp *mlxsw_sp,  				       false, false);  	vid = bridge_device->ops->fid_vid(bridge_device, fid);  	mlxsw_sp_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED, -				    vxlan_fdb_info->eth_addr, vid, dev, false); +				    vxlan_fdb_info->eth_addr, vid, dev, false, +				    false);  	mlxsw_sp_fid_put(fid);  }  |