Skip to content

Commit

Permalink
mlxsw: spectrum: Allow for PVID deletion
Browse files Browse the repository at this point in the history
When PVID is toggled off on a port member in a VLAN filtering bridge or
the PVID VLAN is deleted, make the port drop untagged packets. Reverse
the operation when PVID is toggled back on.

Set the PVID back to the default (1), when leaving the bridge so that
untagged traffic will be directed to the CPU.

Fixes: 56ade8f ("mlxsw: spectrum: Add initial support for Spectrum ASIC")
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>
  • Loading branch information
Ido Schimmel authored and David S. Miller committed Feb 18, 2016
1 parent 148f472 commit 28a01d2
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 9 deletions.
2 changes: 2 additions & 0 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum.c
Original file line number Diff line number Diff line change
Expand Up @@ -2123,6 +2123,8 @@ static int mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port,
if (flush_fdb && mlxsw_sp_port_fdb_flush(mlxsw_sp_port))
netdev_err(mlxsw_sp_port->dev, "Failed to flush FDB\n");

mlxsw_sp_port_pvid_set(mlxsw_sp_port, 1);

mlxsw_sp_port->learning = 0;
mlxsw_sp_port->learning_sync = 0;
mlxsw_sp_port->uc_flood = 0;
Expand Down
1 change: 1 addition & 0 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum.h
Original file line number Diff line number Diff line change
Expand Up @@ -254,5 +254,6 @@ int mlxsw_sp_port_kill_vid(struct net_device *dev,
int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 vfid,
bool set, bool only_uc);
void mlxsw_sp_port_active_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port);
int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);

#endif
69 changes: 60 additions & 9 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,8 @@ static int mlxsw_sp_port_attr_set(struct net_device *dev,
return err;
}

static int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
static int __mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port,
u16 vid)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
char spvid_pl[MLXSW_REG_SPVID_LEN];
Expand All @@ -379,6 +380,53 @@ static int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvid), spvid_pl);
}

static int mlxsw_sp_port_allow_untagged_set(struct mlxsw_sp_port *mlxsw_sp_port,
bool allow)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
char spaft_pl[MLXSW_REG_SPAFT_LEN];

mlxsw_reg_spaft_pack(spaft_pl, mlxsw_sp_port->local_port, allow);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spaft), spaft_pl);
}

int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
{
struct net_device *dev = mlxsw_sp_port->dev;
int err;

if (!vid) {
err = mlxsw_sp_port_allow_untagged_set(mlxsw_sp_port, false);
if (err) {
netdev_err(dev, "Failed to disallow untagged traffic\n");
return err;
}
} else {
err = __mlxsw_sp_port_pvid_set(mlxsw_sp_port, vid);
if (err) {
netdev_err(dev, "Failed to set PVID\n");
return err;
}

/* Only allow if not already allowed. */
if (!mlxsw_sp_port->pvid) {
err = mlxsw_sp_port_allow_untagged_set(mlxsw_sp_port,
true);
if (err) {
netdev_err(dev, "Failed to allow untagged traffic\n");
goto err_port_allow_untagged_set;
}
}
}

mlxsw_sp_port->pvid = vid;
return 0;

err_port_allow_untagged_set:
__mlxsw_sp_port_pvid_set(mlxsw_sp_port, mlxsw_sp_port->pvid);
return err;
}

static int mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp, u16 fid)
{
char sfmr_pl[MLXSW_REG_SFMR_LEN];
Expand Down Expand Up @@ -540,7 +588,12 @@ static int __mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
netdev_err(dev, "Unable to add PVID %d\n", vid_begin);
goto err_port_pvid_set;
}
mlxsw_sp_port->pvid = vid_begin;
} else if (!flag_pvid && old_pvid >= vid_begin && old_pvid <= vid_end) {
err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, 0);
if (err) {
netdev_err(dev, "Unable to del PVID\n");
goto err_port_pvid_set;
}
}

/* Changing activity bits only if HW operation succeded */
Expand Down Expand Up @@ -892,20 +945,18 @@ static int __mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port,
return err;
}

if (init)
goto out;

pvid = mlxsw_sp_port->pvid;
if (pvid >= vid_begin && pvid <= vid_end && pvid != 1) {
/* Default VLAN is always 1 */
err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, 1);
if (pvid >= vid_begin && pvid <= vid_end) {
err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, 0);
if (err) {
netdev_err(dev, "Unable to del PVID %d\n", pvid);
return err;
}
mlxsw_sp_port->pvid = 1;
}

if (init)
goto out;

err = __mlxsw_sp_port_flood_set(mlxsw_sp_port, vid_begin, vid_end,
false, false);
if (err) {
Expand Down

0 comments on commit 28a01d2

Please sign in to comment.