mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-07-10 00:26:34 +00:00
mlxsw: spectrum: Add support for flood control
Add or remove a bridged port from the flooding domain of unknown unicast packets according to user configuration. Signed-off-by: Ido Schimmel <idosch@mellanox.com> Signed-off-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
1b3433a942
commit
0293038e0c
3 changed files with 78 additions and 37 deletions
|
@ -1227,6 +1227,7 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port)
|
||||||
mlxsw_sp_port->local_port = local_port;
|
mlxsw_sp_port->local_port = local_port;
|
||||||
mlxsw_sp_port->learning = 1;
|
mlxsw_sp_port->learning = 1;
|
||||||
mlxsw_sp_port->learning_sync = 1;
|
mlxsw_sp_port->learning_sync = 1;
|
||||||
|
mlxsw_sp_port->uc_flood = 1;
|
||||||
mlxsw_sp_port->pvid = 1;
|
mlxsw_sp_port->pvid = 1;
|
||||||
|
|
||||||
mlxsw_sp_port->pcpu_stats =
|
mlxsw_sp_port->pcpu_stats =
|
||||||
|
|
|
@ -86,6 +86,7 @@ struct mlxsw_sp_port {
|
||||||
u8 stp_state;
|
u8 stp_state;
|
||||||
u8 learning:1,
|
u8 learning:1,
|
||||||
learning_sync:1,
|
learning_sync:1,
|
||||||
|
uc_flood:1,
|
||||||
bridged:1;
|
bridged:1;
|
||||||
u16 pvid;
|
u16 pvid;
|
||||||
/* 802.1Q bridge VLANs */
|
/* 802.1Q bridge VLANs */
|
||||||
|
|
|
@ -66,7 +66,8 @@ static int mlxsw_sp_port_attr_get(struct net_device *dev,
|
||||||
case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
|
case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
|
||||||
attr->u.brport_flags =
|
attr->u.brport_flags =
|
||||||
(mlxsw_sp_port->learning ? BR_LEARNING : 0) |
|
(mlxsw_sp_port->learning ? BR_LEARNING : 0) |
|
||||||
(mlxsw_sp_port->learning_sync ? BR_LEARNING_SYNC : 0);
|
(mlxsw_sp_port->learning_sync ? BR_LEARNING_SYNC : 0) |
|
||||||
|
(mlxsw_sp_port->uc_flood ? BR_FLOOD : 0);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
@ -123,15 +124,89 @@ static int mlxsw_sp_port_attr_stp_state_set(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||||
return mlxsw_sp_port_stp_state_set(mlxsw_sp_port, state);
|
return mlxsw_sp_port_stp_state_set(mlxsw_sp_port, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __mlxsw_sp_port_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||||
|
u16 fid_begin, u16 fid_end, bool set,
|
||||||
|
bool only_uc)
|
||||||
|
{
|
||||||
|
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
|
||||||
|
u16 range = fid_end - fid_begin + 1;
|
||||||
|
char *sftr_pl;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL);
|
||||||
|
if (!sftr_pl)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_UC, fid_begin,
|
||||||
|
MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST, range,
|
||||||
|
mlxsw_sp_port->local_port, set);
|
||||||
|
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl);
|
||||||
|
if (err)
|
||||||
|
goto buffer_out;
|
||||||
|
|
||||||
|
/* Flooding control allows one to decide whether a given port will
|
||||||
|
* flood unicast traffic for which there is no FDB entry.
|
||||||
|
*/
|
||||||
|
if (only_uc)
|
||||||
|
goto buffer_out;
|
||||||
|
|
||||||
|
mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_BM, fid_begin,
|
||||||
|
MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST, range,
|
||||||
|
mlxsw_sp_port->local_port, set);
|
||||||
|
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl);
|
||||||
|
|
||||||
|
buffer_out:
|
||||||
|
kfree(sftr_pl);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mlxsw_sp_port_uc_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||||
|
bool set)
|
||||||
|
{
|
||||||
|
struct net_device *dev = mlxsw_sp_port->dev;
|
||||||
|
u16 vid, last_visited_vid;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) {
|
||||||
|
err = __mlxsw_sp_port_flood_set(mlxsw_sp_port, vid, vid, set,
|
||||||
|
true);
|
||||||
|
if (err) {
|
||||||
|
last_visited_vid = vid;
|
||||||
|
goto err_port_flood_set;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_port_flood_set:
|
||||||
|
for_each_set_bit(vid, mlxsw_sp_port->active_vlans, last_visited_vid)
|
||||||
|
__mlxsw_sp_port_flood_set(mlxsw_sp_port, vid, vid, !set, true);
|
||||||
|
netdev_err(dev, "Failed to configure unicast flooding\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port,
|
static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||||
struct switchdev_trans *trans,
|
struct switchdev_trans *trans,
|
||||||
unsigned long brport_flags)
|
unsigned long brport_flags)
|
||||||
{
|
{
|
||||||
|
unsigned long uc_flood = mlxsw_sp_port->uc_flood ? BR_FLOOD : 0;
|
||||||
|
bool set;
|
||||||
|
int err;
|
||||||
|
|
||||||
if (switchdev_trans_ph_prepare(trans))
|
if (switchdev_trans_ph_prepare(trans))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if ((uc_flood ^ brport_flags) & BR_FLOOD) {
|
||||||
|
set = mlxsw_sp_port->uc_flood ? false : true;
|
||||||
|
err = mlxsw_sp_port_uc_flood_set(mlxsw_sp_port, set);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
mlxsw_sp_port->uc_flood = brport_flags & BR_FLOOD ? 1 : 0;
|
||||||
mlxsw_sp_port->learning = brport_flags & BR_LEARNING ? 1 : 0;
|
mlxsw_sp_port->learning = brport_flags & BR_LEARNING ? 1 : 0;
|
||||||
mlxsw_sp_port->learning_sync = brport_flags & BR_LEARNING_SYNC ? 1 : 0;
|
mlxsw_sp_port->learning_sync = brport_flags & BR_LEARNING_SYNC ? 1 : 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,42 +322,6 @@ static int mlxsw_sp_port_fid_unmap(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid)
|
||||||
return mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, false, fid, fid);
|
return mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, false, fid, fid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __mlxsw_sp_port_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
||||||
u16 fid_begin, u16 fid_end, bool set,
|
|
||||||
bool only_uc)
|
|
||||||
{
|
|
||||||
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
|
|
||||||
u16 range = fid_end - fid_begin + 1;
|
|
||||||
char *sftr_pl;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL);
|
|
||||||
if (!sftr_pl)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_UC, fid_begin,
|
|
||||||
MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST, range,
|
|
||||||
mlxsw_sp_port->local_port, set);
|
|
||||||
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl);
|
|
||||||
if (err)
|
|
||||||
goto buffer_out;
|
|
||||||
|
|
||||||
/* Flooding control allows one to decide whether a given port will
|
|
||||||
* flood unicast traffic for which there is no FDB entry.
|
|
||||||
*/
|
|
||||||
if (only_uc)
|
|
||||||
goto buffer_out;
|
|
||||||
|
|
||||||
mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_BM, fid_begin,
|
|
||||||
MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST, range,
|
|
||||||
mlxsw_sp_port->local_port, set);
|
|
||||||
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl);
|
|
||||||
|
|
||||||
buffer_out:
|
|
||||||
kfree(sftr_pl);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mlxsw_sp_port_add_vids(struct net_device *dev, u16 vid_begin,
|
static int mlxsw_sp_port_add_vids(struct net_device *dev, u16 vid_begin,
|
||||||
u16 vid_end)
|
u16 vid_end)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue