Skip to content

Commit

Permalink
mlxsw: spectrum: Set port's mode according to FID mappings
Browse files Browse the repository at this point in the history
We currently transition the port to "Virtual mode" upon the creation of
its first VLAN upper, as we need to classify incoming packets to a FID
using {Port, VID} and not only the VID.

However, it's more appropriate to transition the port to this mode when
the {Port, VID} are actually mapped to a FID. Either during the
enslavement of the VLAN upper to a VLAN-unaware bridge or the
configuration of a router port.

Do this change now in preparation for the introduction of the FID core,
where this operation will be encapsulated.

To prevent regressions, this patch also explicitly configures an OVS
slave to "Virtual mode". Otherwise, a packet that didn't hit an ACL rule
could be classified to an existing FID based on a global VID-to-FID
mapping, thus not incurring a FID mis-classification, which would
otherwise trap the packet to the CPU to be processed by the OVS daemon.

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 May 26, 2017
1 parent 9341b98 commit 4aafc36
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 28 deletions.
55 changes: 30 additions & 25 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum.c
Original file line number Diff line number Diff line change
Expand Up @@ -1398,7 +1398,7 @@ int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin,
return 0;
}

static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
{
enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID;
u16 vid, last_visited_vid;
Expand Down Expand Up @@ -1428,7 +1428,7 @@ static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
return err;
}

static int mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
int mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
{
enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID;
u16 vid;
Expand Down Expand Up @@ -1501,26 +1501,13 @@ static int mlxsw_sp_port_add_vid(struct net_device *dev,
if (!mlxsw_sp_vport)
return -ENOMEM;

/* When adding the first VLAN interface on a bridged port we need to
* transition all the active 802.1Q bridge VLANs to use explicit
* {Port, VID} to FID mappings and set the port's mode to Virtual mode.
*/
if (list_is_singular(&mlxsw_sp_port->vports_list)) {
err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
if (err)
goto err_port_vp_mode_trans;
}

err = mlxsw_sp_port_vlan_set(mlxsw_sp_vport, vid, vid, true, untagged);
if (err)
goto err_port_add_vid;

return 0;

err_port_add_vid:
if (list_is_singular(&mlxsw_sp_port->vports_list))
mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
err_port_vp_mode_trans:
mlxsw_sp_port_vport_destroy(mlxsw_sp_vport);
return err;
}
Expand Down Expand Up @@ -1551,13 +1538,6 @@ static int mlxsw_sp_port_kill_vid(struct net_device *dev,
if (f && !WARN_ON(!f->leave))
f->leave(mlxsw_sp_vport);

/* When removing the last VLAN interface on a bridged port we need to
* transition all active 802.1Q bridge VLANs to use VID to FID
* mappings and set port's mode to VLAN mode.
*/
if (list_is_singular(&mlxsw_sp_port->vports_list))
mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);

mlxsw_sp_port_vport_destroy(mlxsw_sp_vport);

return 0;
Expand Down Expand Up @@ -4382,9 +4362,12 @@ static int mlxsw_sp_port_ovs_join(struct mlxsw_sp_port *mlxsw_sp_port)
{
int err;

err = mlxsw_sp_port_stp_set(mlxsw_sp_port, true);
err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true);
if (err)
return err;
err = mlxsw_sp_port_stp_set(mlxsw_sp_port, true);
if (err)
goto err_port_stp_set;
err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, 2, VLAN_N_VID - 1,
true, false);
if (err)
Expand All @@ -4393,6 +4376,8 @@ static int mlxsw_sp_port_ovs_join(struct mlxsw_sp_port *mlxsw_sp_port)

err_port_vlan_set:
mlxsw_sp_port_stp_set(mlxsw_sp_port, false);
err_port_stp_set:
mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
return err;
}

Expand All @@ -4401,6 +4386,7 @@ static void mlxsw_sp_port_ovs_leave(struct mlxsw_sp_port *mlxsw_sp_port)
mlxsw_sp_port_vlan_set(mlxsw_sp_port, 2, VLAN_N_VID - 1,
false, false);
mlxsw_sp_port_stp_set(mlxsw_sp_port, false);
mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
}

static int mlxsw_sp_netdevice_port_upper_event(struct net_device *dev,
Expand Down Expand Up @@ -4695,6 +4681,7 @@ static int mlxsw_sp_vport_fid_map(struct mlxsw_sp_port *mlxsw_sp_vport, u16 fid,
static int mlxsw_sp_vport_vfid_join(struct mlxsw_sp_port *mlxsw_sp_vport,
struct net_device *br_dev)
{
struct mlxsw_sp_port *mlxsw_sp_port;
struct mlxsw_sp_fid *f;
int err;

Expand All @@ -4713,13 +4700,23 @@ static int mlxsw_sp_vport_vfid_join(struct mlxsw_sp_port *mlxsw_sp_vport,
if (err)
goto err_vport_fid_map;

mlxsw_sp_port = mlxsw_sp_vport_port(mlxsw_sp_vport);
if (mlxsw_sp_port->nr_port_vid_map++ == 0) {
err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
if (err)
goto err_port_vp_mode_trans;
}

mlxsw_sp_vport_fid_set(mlxsw_sp_vport, f);
f->ref_count++;

netdev_dbg(mlxsw_sp_vport->dev, "Joined FID=%d\n", f->fid);

return 0;

err_port_vp_mode_trans:
mlxsw_sp_port->nr_port_vid_map--;
mlxsw_sp_vport_fid_map(mlxsw_sp_vport, f->fid, false);
err_vport_fid_map:
mlxsw_sp_vport_flood_set(mlxsw_sp_vport, f->fid, false);
err_vport_flood_set:
Expand All @@ -4731,17 +4728,25 @@ static int mlxsw_sp_vport_vfid_join(struct mlxsw_sp_port *mlxsw_sp_vport,
static void mlxsw_sp_vport_vfid_leave(struct mlxsw_sp_port *mlxsw_sp_vport)
{
struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport);
struct mlxsw_sp_port *mlxsw_sp_port;

netdev_dbg(mlxsw_sp_vport->dev, "Left FID=%d\n", f->fid);

mlxsw_sp_vport_fid_set(mlxsw_sp_vport, NULL);
f->ref_count--;

mlxsw_sp_port = mlxsw_sp_vport_port(mlxsw_sp_vport);
if (mlxsw_sp_port->nr_port_vid_map == 1)
mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
mlxsw_sp_port->nr_port_vid_map--;

mlxsw_sp_vport_fid_map(mlxsw_sp_vport, f->fid, false);

mlxsw_sp_vport_flood_set(mlxsw_sp_vport, f->fid, false);

mlxsw_sp_port_fdb_flush(mlxsw_sp_vport, f->fid);

mlxsw_sp_vport_fid_set(mlxsw_sp_vport, NULL);
if (--f->ref_count == 0)
if (f->ref_count == 0)
mlxsw_sp_vfid_destroy(mlxsw_sp_vport->mlxsw_sp, f);
}

Expand Down
11 changes: 11 additions & 0 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum.h
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ struct mlxsw_sp_port {
struct delayed_work update_dw;
} hw_stats;
struct mlxsw_sp_port_sample *sample;
unsigned int nr_port_vid_map; /* {Port, VID} => FID mappings */
};

bool mlxsw_sp_port_dev_check(const struct net_device *dev);
Expand Down Expand Up @@ -343,6 +344,14 @@ mlxsw_sp_port_vport_find_by_fid(const struct mlxsw_sp_port *mlxsw_sp_port,
return NULL;
}

static inline struct mlxsw_sp_port *
mlxsw_sp_vport_port(const struct mlxsw_sp_port *mlxsw_sp_vport)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp;

return mlxsw_sp->ports[mlxsw_sp_vport->local_port];
}

static inline struct mlxsw_sp_fid *mlxsw_sp_fid_find(struct mlxsw_sp *mlxsw_sp,
u16 fid)
{
Expand Down Expand Up @@ -446,6 +455,8 @@ int mlxsw_sp_port_vid_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid,
int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid,
bool learn_enable);
int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);
int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port);
int mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port);

#ifdef CONFIG_MLXSW_SPECTRUM_DCB

Expand Down
23 changes: 21 additions & 2 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
Original file line number Diff line number Diff line change
Expand Up @@ -3111,6 +3111,7 @@ static int mlxsw_sp_vport_rif_sp_join(struct mlxsw_sp_port *mlxsw_sp_vport,
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp;
u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport);
struct mlxsw_sp_port *mlxsw_sp_port;
struct mlxsw_sp_rif *rif;
int err;

Expand All @@ -3130,13 +3131,23 @@ static int mlxsw_sp_vport_rif_sp_join(struct mlxsw_sp_port *mlxsw_sp_vport,
if (err)
goto err_port_vid_stp_set;

mlxsw_sp_port = mlxsw_sp_vport_port(mlxsw_sp_vport);
if (mlxsw_sp_port->nr_port_vid_map++ == 0) {
err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
if (err)
goto err_port_vp_mode_trans;
}

mlxsw_sp_vport_fid_set(mlxsw_sp_vport, rif->f);
rif->f->ref_count++;

netdev_dbg(mlxsw_sp_vport->dev, "Joined FID=%d\n", rif->f->fid);

return 0;

err_port_vp_mode_trans:
mlxsw_sp_port->nr_port_vid_map--;
mlxsw_sp_port_vid_stp_set(mlxsw_sp_vport, vid, BR_STATE_BLOCKING);
err_port_vid_stp_set:
mlxsw_sp_port_vid_learning_set(mlxsw_sp_vport, vid, true);
err_port_vid_learning_set:
Expand All @@ -3149,13 +3160,21 @@ static void mlxsw_sp_vport_rif_sp_leave(struct mlxsw_sp_port *mlxsw_sp_vport)
{
struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport);
u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport);
struct mlxsw_sp_port *mlxsw_sp_port;

netdev_dbg(mlxsw_sp_vport->dev, "Left FID=%d\n", f->fid);

f->ref_count--;
mlxsw_sp_vport_fid_set(mlxsw_sp_vport, NULL);

mlxsw_sp_port = mlxsw_sp_vport_port(mlxsw_sp_vport);
if (mlxsw_sp_port->nr_port_vid_map == 1)
mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
mlxsw_sp_port->nr_port_vid_map--;
mlxsw_sp_port_vid_stp_set(mlxsw_sp_vport, vid, BR_STATE_BLOCKING);
mlxsw_sp_port_vid_learning_set(mlxsw_sp_vport, vid, true);
mlxsw_sp_vport_fid_set(mlxsw_sp_vport, NULL);
if (--f->ref_count == 0)

if (f->ref_count == 0)
mlxsw_sp_vport_rif_sp_destroy(mlxsw_sp_vport, f->rif);
}

Expand Down
2 changes: 1 addition & 1 deletion drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@ static int mlxsw_sp_port_fid_map(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid,
/* If port doesn't have vPorts, then it can use the global
* VID-to-FID mapping.
*/
if (list_empty(&mlxsw_sp_port->vports_list))
if (mlxsw_sp_port->nr_port_vid_map == 0)
return 0;

return mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, valid, fid, fid);
Expand Down

0 comments on commit 4aafc36

Please sign in to comment.