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

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.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents bf9b8556 cdbde7ed
......@@ -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
====================
......
......@@ -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),
......
......@@ -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;
......
......@@ -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);
......
......@@ -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);
}
......
......@@ -510,6 +510,9 @@ mlxsw_sp_trap_policer_items_arr[] = {
{
.policer = MLXSW_SP_TRAP_POLICER(20, 10240, 4096),
},
{
.policer = MLXSW_SP_TRAP_POLICER(21, 128, 128),
},
};
static const struct mlxsw_sp_trap_group_item mlxsw_sp_trap_group_items_arr[] = {
......@@ -628,6 +631,11 @@ static const struct mlxsw_sp_trap_group_item mlxsw_sp_trap_group_items_arr[] = {
.hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_FLOW_LOGGING,
.priority = 4,
},
{
.group = DEVLINK_TRAP_GROUP_GENERIC(EAPOL, 21),
.hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_EAPOL,
.priority = 5,
},
};
static const struct mlxsw_sp_trap_item mlxsw_sp_trap_items_arr[] = {
......@@ -1160,6 +1168,23 @@ static const struct mlxsw_sp_trap_item mlxsw_sp_trap_items_arr[] = {
MLXSW_SP_RXL_DISCARD(ROUTER3, L3_DISCARDS),
},
},
{
.trap = MLXSW_SP_TRAP_CONTROL(EAPOL, EAPOL, TRAP),
.listeners_arr = {
MLXSW_SP_RXL_NO_MARK(EAPOL, EAPOL, TRAP_TO_CPU, true),
},
},
{
.trap = MLXSW_SP_TRAP_DROP(LOCKED_PORT, L2_DROPS),
.listeners_arr = {
MLXSW_RXL_DIS(mlxsw_sp_rx_drop_listener, FDB_MISS,
TRAP_EXCEPTION_TO_CPU, false,
SP_L2_DISCARDS, DISCARD, SP_L2_DISCARDS),
MLXSW_RXL_DIS(mlxsw_sp_rx_drop_listener, FDB_MISMATCH,
TRAP_EXCEPTION_TO_CPU, false,
SP_L2_DISCARDS, DISCARD, SP_L2_DISCARDS),
},
},
};
static struct mlxsw_sp_trap_policer_item *
......
......@@ -25,6 +25,8 @@ enum {
MLXSW_TRAP_ID_IGMP_V2_LEAVE = 0x33,
MLXSW_TRAP_ID_IGMP_V3_REPORT = 0x34,
MLXSW_TRAP_ID_PKT_SAMPLE = 0x38,
MLXSW_TRAP_ID_FDB_MISS = 0x3A,
MLXSW_TRAP_ID_FDB_MISMATCH = 0x3B,
MLXSW_TRAP_ID_FID_MISS = 0x3D,
MLXSW_TRAP_ID_DECAP_ECN0 = 0x40,
MLXSW_TRAP_ID_MTUERROR = 0x52,
......
......@@ -894,6 +894,8 @@ enum devlink_trap_generic_id {
DEVLINK_TRAP_GENERIC_ID_ESP_PARSING,
DEVLINK_TRAP_GENERIC_ID_BLACKHOLE_NEXTHOP,
DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER,
DEVLINK_TRAP_GENERIC_ID_EAPOL,
DEVLINK_TRAP_GENERIC_ID_LOCKED_PORT,
/* Add new generic trap IDs above */
__DEVLINK_TRAP_GENERIC_ID_MAX,
......@@ -930,6 +932,7 @@ enum devlink_trap_group_generic_id {
DEVLINK_TRAP_GROUP_GENERIC_ID_ACL_SAMPLE,
DEVLINK_TRAP_GROUP_GENERIC_ID_ACL_TRAP,
DEVLINK_TRAP_GROUP_GENERIC_ID_PARSER_ERROR_DROPS,
DEVLINK_TRAP_GROUP_GENERIC_ID_EAPOL,
/* Add new generic trap group IDs above */
__DEVLINK_TRAP_GROUP_GENERIC_ID_MAX,
......@@ -1121,6 +1124,10 @@ enum devlink_trap_group_generic_id {
"blackhole_nexthop"
#define DEVLINK_TRAP_GENERIC_NAME_DMAC_FILTER \
"dmac_filter"
#define DEVLINK_TRAP_GENERIC_NAME_EAPOL \
"eapol"
#define DEVLINK_TRAP_GENERIC_NAME_LOCKED_PORT \
"locked_port"
#define DEVLINK_TRAP_GROUP_GENERIC_NAME_L2_DROPS \
"l2_drops"
......@@ -1174,6 +1181,8 @@ enum devlink_trap_group_generic_id {
"acl_trap"
#define DEVLINK_TRAP_GROUP_GENERIC_NAME_PARSER_ERROR_DROPS \
"parser_error_drops"
#define DEVLINK_TRAP_GROUP_GENERIC_NAME_EAPOL \
"eapol"
#define DEVLINK_TRAP_GENERIC(_type, _init_action, _id, _group_id, \
_metadata_cap) \
......
......@@ -248,6 +248,7 @@ struct switchdev_notifier_fdb_info {
u16 vid;
u8 added_by_user:1,
is_local:1,
locked:1,
offloaded:1;
};
......
......@@ -166,13 +166,14 @@ static int br_switchdev_event(struct notifier_block *unused,
case SWITCHDEV_FDB_ADD_TO_BRIDGE:
fdb_info = ptr;
err = br_fdb_external_learn_add(br, p, fdb_info->addr,
fdb_info->vid, false);
fdb_info->vid,
fdb_info->locked, false);
if (err) {
err = notifier_from_errno(err);
break;
}
br_fdb_offloaded_set(br, p, fdb_info->addr,
fdb_info->vid, true);
fdb_info->vid, fdb_info->offloaded);
break;
case SWITCHDEV_FDB_DEL_TO_BRIDGE:
fdb_info = ptr;
......
......@@ -1139,7 +1139,7 @@ static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge *br,
"FDB entry towards bridge must be permanent");
return -EINVAL;
}
err = br_fdb_external_learn_add(br, p, addr, vid, true);
err = br_fdb_external_learn_add(br, p, addr, vid, false, true);
} else {
spin_lock_bh(&br->hash_lock);
err = fdb_add_entry(br, p, addr, ndm, nlh_flags, vid, nfea_tb);
......@@ -1377,7 +1377,7 @@ void br_fdb_unsync_static(struct net_bridge *br, struct net_bridge_port *p)
}
int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
const unsigned char *addr, u16 vid,
const unsigned char *addr, u16 vid, bool locked,
bool swdev_notify)
{
struct net_bridge_fdb_entry *fdb;
......@@ -1386,6 +1386,9 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
trace_br_fdb_external_learn_add(br, p, addr, vid);
if (locked && (!p || !(p->flags & BR_PORT_MAB)))
return -EINVAL;
spin_lock_bh(&br->hash_lock);
fdb = br_fdb_find(br, addr, vid);
......@@ -1398,6 +1401,9 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
if (!p)
flags |= BIT(BR_FDB_LOCAL);
if (locked)
flags |= BIT(BR_FDB_LOCKED);
fdb = fdb_create(br, p, addr, vid, flags);
if (!fdb) {
err = -ENOMEM;
......@@ -1405,6 +1411,13 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
}
fdb_notify(br, fdb, RTM_NEWNEIGH, swdev_notify);
} else {
if (locked &&
(!test_bit(BR_FDB_LOCKED, &fdb->flags) ||
READ_ONCE(fdb->dst) != p)) {
err = -EINVAL;
goto err_unlock;
}
fdb->updated = jiffies;
if (READ_ONCE(fdb->dst) != p) {
......@@ -1421,6 +1434,11 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
modified = true;
}
if (locked != test_bit(BR_FDB_LOCKED, &fdb->flags)) {
change_bit(BR_FDB_LOCKED, &fdb->flags);
modified = true;
}
if (swdev_notify)
set_bit(BR_FDB_ADDED_BY_USER, &fdb->flags);
......
......@@ -811,7 +811,7 @@ int br_fdb_sync_static(struct net_bridge *br, struct net_bridge_port *p);
void br_fdb_unsync_static(struct net_bridge *br, struct net_bridge_port *p);
int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
const unsigned char *addr, u16 vid,
bool swdev_notify);
bool locked, bool swdev_notify);
int br_fdb_external_learn_del(struct net_bridge *br, struct net_bridge_port *p,
const unsigned char *addr, u16 vid,
bool swdev_notify);
......
......@@ -71,7 +71,7 @@ bool nbp_switchdev_allowed_egress(const struct net_bridge_port *p,
}
/* Flags that can be offloaded to hardware */
#define BR_PORT_FLAGS_HW_OFFLOAD (BR_LEARNING | BR_FLOOD | \
#define BR_PORT_FLAGS_HW_OFFLOAD (BR_LEARNING | BR_FLOOD | BR_PORT_MAB | \
BR_MCAST_FLOOD | BR_BCAST_FLOOD | BR_PORT_LOCKED | \
BR_HAIRPIN_MODE | BR_ISOLATED | BR_MULTICAST_TO_UNICAST)
......@@ -136,6 +136,7 @@ static void br_switchdev_fdb_populate(struct net_bridge *br,
item->added_by_user = test_bit(BR_FDB_ADDED_BY_USER, &fdb->flags);
item->offloaded = test_bit(BR_FDB_OFFLOADED, &fdb->flags);
item->is_local = test_bit(BR_FDB_LOCAL, &fdb->flags);
item->locked = false;
item->info.dev = (!p || item->is_local) ? br->dev : p->dev;
item->info.ctx = ctx;
}
......@@ -146,6 +147,9 @@ br_switchdev_fdb_notify(struct net_bridge *br,
{
struct switchdev_notifier_fdb_info item;
if (test_bit(BR_FDB_LOCKED, &fdb->flags))
return;
br_switchdev_fdb_populate(br, &item, fdb, NULL);
switch (type) {
......
......@@ -11734,6 +11734,8 @@ static const struct devlink_trap devlink_trap_generic[] = {
DEVLINK_TRAP(ESP_PARSING, DROP),
DEVLINK_TRAP(BLACKHOLE_NEXTHOP, DROP),
DEVLINK_TRAP(DMAC_FILTER, DROP),
DEVLINK_TRAP(EAPOL, CONTROL),
DEVLINK_TRAP(LOCKED_PORT, DROP),
};
#define DEVLINK_TRAP_GROUP(_id) \
......@@ -11769,6 +11771,7 @@ static const struct devlink_trap_group devlink_trap_group_generic[] = {
DEVLINK_TRAP_GROUP(ACL_SAMPLE),
DEVLINK_TRAP_GROUP(ACL_TRAP),
DEVLINK_TRAP_GROUP(PARSER_ERROR_DROPS),
DEVLINK_TRAP_GROUP(EAPOL),
};
static int devlink_trap_generic_verify(const struct devlink_trap *trap)
......
......@@ -83,6 +83,7 @@ ALL_TESTS="
ptp_general_test
flow_action_sample_test
flow_action_trap_test
eapol_test
"
NUM_NETIFS=4
source $lib_dir/lib.sh
......@@ -677,6 +678,27 @@ flow_action_trap_test()
tc qdisc del dev $rp1 clsact
}
eapol_payload_get()
{
local source_mac=$1; shift
local p
p=$(:
)"01:80:C2:00:00:03:"$( : ETH daddr
)"$source_mac:"$( : ETH saddr
)"88:8E:"$( : ETH type
)
echo $p
}
eapol_test()
{
local h1mac=$(mac_get $h1)
devlink_trap_stats_test "EAPOL" "eapol" $MZ $h1 -c 1 \
$(eapol_payload_get $h1mac) -p 100 -q
}
trap cleanup EXIT
setup_prepare
......
......@@ -14,6 +14,7 @@ ALL_TESTS="
ingress_stp_filter_test
port_list_is_empty_test
port_loopback_filter_test
locked_port_test
"
NUM_NETIFS=4
source $lib_dir/tc_common.sh
......@@ -420,6 +421,110 @@ port_loopback_filter_test()
port_loopback_filter_uc_test
}
locked_port_miss_test()
{
local trap_name="locked_port"
local smac=00:11:22:33:44:55
bridge link set dev $swp1 learning off
bridge link set dev $swp1 locked on
RET=0
devlink_trap_stats_check $trap_name $MZ $h1 -c 1 \
-a $smac -b $(mac_get $h2) -A 192.0.2.1 -B 192.0.2.2 -p 100 -q
check_fail $? "Trap stats increased before setting action to \"trap\""
devlink_trap_action_set $trap_name "trap"
devlink_trap_stats_check $trap_name $MZ $h1 -c 1 \
-a $smac -b $(mac_get $h2) -A 192.0.2.1 -B 192.0.2.2 -p 100 -q
check_err $? "Trap stats did not increase when should"
devlink_trap_action_set $trap_name "drop"
devlink_trap_stats_check $trap_name $MZ $h1 -c 1 \
-a $smac -b $(mac_get $h2) -A 192.0.2.1 -B 192.0.2.2 -p 100 -q
check_fail $? "Trap stats increased after setting action to \"drop\""
devlink_trap_action_set $trap_name "trap"
bridge fdb replace $smac dev $swp1 master static vlan 1
devlink_trap_stats_check $trap_name $MZ $h1 -c 1 \
-a $smac -b $(mac_get $h2) -A 192.0.2.1 -B 192.0.2.2 -p 100 -q
check_fail $? "Trap stats increased after adding an FDB entry"
bridge fdb del $smac dev $swp1 master static vlan 1
bridge link set dev $swp1 locked off
devlink_trap_stats_check $trap_name $MZ $h1 -c 1 \
-a $smac -b $(mac_get $h2) -A 192.0.2.1 -B 192.0.2.2 -p 100 -q
check_fail $? "Trap stats increased after unlocking port"
log_test "Locked port - FDB miss"
devlink_trap_action_set $trap_name "drop"
bridge link set dev $swp1 learning on
}
locked_port_mismatch_test()
{
local trap_name="locked_port"
local smac=00:11:22:33:44:55
bridge link set dev $swp1 learning off
bridge link set dev $swp1 locked on
RET=0
bridge fdb replace $smac dev $swp2 master static vlan 1
devlink_trap_stats_check $trap_name $MZ $h1 -c 1 \
-a $smac -b $(mac_get $h2) -A 192.0.2.1 -B 192.0.2.2 -p 100 -q
check_fail $? "Trap stats increased before setting action to \"trap\""
devlink_trap_action_set $trap_name "trap"
devlink_trap_stats_check $trap_name $MZ $h1 -c 1 \
-a $smac -b $(mac_get $h2) -A 192.0.2.1 -B 192.0.2.2 -p 100 -q
check_err $? "Trap stats did not increase when should"
devlink_trap_action_set $trap_name "drop"
devlink_trap_stats_check $trap_name $MZ $h1 -c 1 \
-a $smac -b $(mac_get $h2) -A 192.0.2.1 -B 192.0.2.2 -p 100 -q
check_fail $? "Trap stats increased after setting action to \"drop\""
devlink_trap_action_set $trap_name "trap"
bridge link set dev $swp1 locked off
devlink_trap_stats_check $trap_name $MZ $h1 -c 1 \
-a $smac -b $(mac_get $h2) -A 192.0.2.1 -B 192.0.2.2 -p 100 -q
check_fail $? "Trap stats increased after unlocking port"
bridge link set dev $swp1 locked on
bridge fdb replace $smac dev $swp1 master static vlan 1
devlink_trap_stats_check $trap_name $MZ $h1 -c 1 \
-a $smac -b $(mac_get $h2) -A 192.0.2.1 -B 192.0.2.2 -p 100 -q
check_fail $? "Trap stats increased after replacing an FDB entry"
bridge fdb del $smac dev $swp1 master static vlan 1
devlink_trap_action_set $trap_name "drop"
log_test "Locked port - FDB mismatch"
bridge link set dev $swp1 locked off
bridge link set dev $swp1 learning on
}
locked_port_test()
{
locked_port_miss_test
locked_port_mismatch_test
}
trap cleanup EXIT
setup_prepare
......
......@@ -34,6 +34,7 @@ ALL_TESTS="
nexthop_obj_bucket_offload_test
nexthop_obj_blackhole_offload_test
nexthop_obj_route_offload_test
bridge_locked_port_test
devlink_reload_test
"
NUM_NETIFS=2
......@@ -917,6 +918,36 @@ nexthop_obj_route_offload_test()
simple_if_fini $swp1 192.0.2.1/24 2001:db8:1::1/64
}
bridge_locked_port_test()
{
RET=0
ip link add name br1 up type bridge vlan_filtering 0
ip link add link $swp1 name $swp1.10 type vlan id 10
ip link set dev $swp1.10 master br1
bridge link set dev $swp1.10 locked on
check_fail $? "managed to set locked flag on a VLAN upper"
ip link set dev $swp1.10 nomaster
ip link set dev $swp1 master br1
bridge link set dev $swp1 locked on
check_fail $? "managed to set locked flag on a bridge port that has a VLAN upper"
ip link del dev $swp1.10
bridge link set dev $swp1 locked on
ip link add link $swp1 name $swp1.10 type vlan id 10
check_fail $? "managed to configure a VLAN upper on a locked port"
log_test "bridge locked port"
ip link del dev $swp1.10 &> /dev/null
ip link del dev br1
}
devlink_reload_test()
{
# Test that after executing all the above configuration tests, a
......
......@@ -503,25 +503,30 @@ devlink_trap_drop_cleanup()
tc filter del dev $dev egress protocol $proto pref $pref handle $handle flower
}
devlink_trap_stats_test()
devlink_trap_stats_check()
{
local test_name=$1; shift
local trap_name=$1; shift
local send_one="$@"
local t0_packets
local t1_packets
RET=0
t0_packets=$(devlink_trap_rx_packets_get $trap_name)
$send_one && sleep 1
t1_packets=$(devlink_trap_rx_packets_get $trap_name)
if [[ $t1_packets -eq $t0_packets ]]; then
check_err 1 "Trap stats did not increase"
fi
[[ $t1_packets -ne $t0_packets ]]
}
devlink_trap_stats_test()
{
local test_name=$1; shift
RET=0
devlink_trap_stats_check "$@"
check_err $? "Trap stats did not increase"
log_test "$test_name"
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment