Commit 0cb9ed57 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'mlxsw-add-802-1x-and-mab-offload-support'

Petr Machata says:

====================
mlxsw: Add 802.1X and MAB offload support

This patchset adds 802.1X [1] and MAB [2] offload support in mlxsw.

Patches #1-#3 add the required switchdev interfaces.

Patches #4-#5 add the required packet traps for 802.1X.

Patches #6-#10 are small preparations in mlxsw.

Patch #11 adds locked bridge port support in mlxsw.

Patches #12-#15 add mlxsw selftests. The patchset was also tested with
the generic forwarding selftest ('bridge_locked_port.sh').

[1] https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit/?id=a21d9a670d81103db7f788de1a4a4a6e4b891a0b
[2] https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit/?id=a35ec8e38cdd1766f29924ca391a01de20163931
====================

Link: https://lore.kernel.org/r/cover.1667902754.git.petrm@nvidia.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents bf9b8556 cdbde7ed
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -485,6 +485,16 @@ be added to the following table:
     - Traps incoming packets that the device decided to drop because
       the destination MAC is not configured in the MAC table and
       the interface is not in promiscuous mode
   * - ``eapol``
     - ``control``
     - Traps "Extensible Authentication Protocol over LAN" (EAPOL) packets
       specified in IEEE 802.1X
   * - ``locked_port``
     - ``drop``
     - Traps packets that the device decided to drop because they failed the
       locked bridge port check. That is, packets that were received via a
       locked port and whose {SMAC, VID} does not correspond to an FDB entry
       pointing to the port

Driver-specific Packet Traps
============================
@@ -589,6 +599,9 @@ narrow. The description of these groups must be added to the following table:
   * - ``parser_error_drops``
     - Contains packet traps for packets that were marked by the device during
       parsing as erroneous
   * - ``eapol``
     - Contains packet traps for "Extensible Authentication Protocol over LAN"
       (EAPOL) packets specified in IEEE 802.1X

Packet Trap Policers
====================
+35 −0
Original line number Diff line number Diff line
@@ -2046,6 +2046,39 @@ static inline void mlxsw_reg_spvmlr_pack(char *payload, u16 local_port,
	}
}

/* SPFSR - Switch Port FDB Security Register
 * -----------------------------------------
 * Configures the security mode per port.
 */
#define MLXSW_REG_SPFSR_ID 0x2023
#define MLXSW_REG_SPFSR_LEN 0x08

MLXSW_REG_DEFINE(spfsr, MLXSW_REG_SPFSR_ID, MLXSW_REG_SPFSR_LEN);

/* reg_spfsr_local_port
 * Local port.
 * Access: Index
 *
 * Note: not supported for CPU port.
 */
MLXSW_ITEM32_LP(reg, spfsr, 0x00, 16, 0x00, 12);

/* reg_spfsr_security
 * Security checks.
 * 0: disabled (default)
 * 1: enabled
 * Access: RW
 */
MLXSW_ITEM32(reg, spfsr, security, 0x04, 31, 1);

static inline void mlxsw_reg_spfsr_pack(char *payload, u16 local_port,
					bool security)
{
	MLXSW_REG_ZERO(spfsr, payload);
	mlxsw_reg_spfsr_local_port_set(payload, local_port);
	mlxsw_reg_spfsr_security_set(payload, security);
}

/* SPVC - Switch Port VLAN Classification Register
 * -----------------------------------------------
 * Configures the port to identify packets as untagged / single tagged /
@@ -6316,6 +6349,7 @@ enum mlxsw_reg_htgt_trap_group {
	MLXSW_REG_HTGT_TRAP_GROUP_SP_TUNNEL_DISCARDS,
	MLXSW_REG_HTGT_TRAP_GROUP_SP_ACL_DISCARDS,
	MLXSW_REG_HTGT_TRAP_GROUP_SP_BUFFER_DISCARDS,
	MLXSW_REG_HTGT_TRAP_GROUP_SP_EAPOL,

	__MLXSW_REG_HTGT_TRAP_GROUP_MAX,
	MLXSW_REG_HTGT_TRAP_GROUP_MAX = __MLXSW_REG_HTGT_TRAP_GROUP_MAX - 1
@@ -12761,6 +12795,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = {
	MLXSW_REG(svpe),
	MLXSW_REG(sfmr),
	MLXSW_REG(spvmlr),
	MLXSW_REG(spfsr),
	MLXSW_REG(spvc),
	MLXSW_REG(spevet),
	MLXSW_REG(smpe),
+22 −0
Original line number Diff line number Diff line
@@ -466,6 +466,24 @@ int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid,
	return err;
}

int mlxsw_sp_port_security_set(struct mlxsw_sp_port *mlxsw_sp_port, bool enable)
{
	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
	char spfsr_pl[MLXSW_REG_SPFSR_LEN];
	int err;

	if (mlxsw_sp_port->security == enable)
		return 0;

	mlxsw_reg_spfsr_pack(spfsr_pl, mlxsw_sp_port->local_port, enable);
	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spfsr), spfsr_pl);
	if (err)
		return err;

	mlxsw_sp_port->security = enable;
	return 0;
}

int mlxsw_sp_ethtype_to_sver_type(u16 ethtype, u8 *p_sver_type)
{
	switch (ethtype) {
@@ -4742,6 +4760,10 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev,
			NL_SET_ERR_MSG_MOD(extack, "VLAN uppers are only supported with 802.1q VLAN protocol");
			return -EOPNOTSUPP;
		}
		if (is_vlan_dev(upper_dev) && mlxsw_sp_port->security) {
			NL_SET_ERR_MSG_MOD(extack, "VLAN uppers are not supported on a locked port");
			return -EOPNOTSUPP;
		}
		break;
	case NETDEV_CHANGEUPPER:
		upper_dev = info->upper_dev;
+4 −1
Original line number Diff line number Diff line
@@ -321,7 +321,8 @@ struct mlxsw_sp_port {
	struct mlxsw_sp *mlxsw_sp;
	u16 local_port;
	u8 lagged:1,
	   split:1;
	   split:1,
	   security:1;
	u16 pvid;
	u16 lag_id;
	struct {
@@ -687,6 +688,8 @@ int mlxsw_sp_port_vid_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid,
int mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, bool enable);
int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid,
				   bool learn_enable);
int mlxsw_sp_port_security_set(struct mlxsw_sp_port *mlxsw_sp_port,
			       bool enable);
int mlxsw_sp_ethtype_to_sver_type(u16 ethtype, u8 *p_sver_type);
int mlxsw_sp_port_egress_ethtype_set(struct mlxsw_sp_port *mlxsw_sp_port,
				     u16 ethtype);
+53 −11
Original line number Diff line number Diff line
@@ -782,10 +782,25 @@ mlxsw_sp_bridge_port_learning_set(struct mlxsw_sp_port *mlxsw_sp_port,

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 @@ static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp,
	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 @@ static void mlxsw_sp_fdb_notify_mac_lag_process(struct mlxsw_sp *mlxsw_sp,
	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);

@@ -3493,7 +3534,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);
}
Loading