Commit bf73904f authored by Amit Cohen's avatar Amit Cohen Committed by David S. Miller

mlxsw: Add support for 802.1Q FID family

Using the legacy bridge model, there is no VID classification at egress
for 802.1Q FIDs, which means that the VID is maintained.

This behavior cause the limitation that 802.1Q FIDs cannot work with VXLAN.
This limitation stems from the fact that a decapsulated VXLAN packet should
not contain a VLAN tag. If such a packet was to egress from a local port
using a 802.1Q FID, it would "maintain" its VLAN on egress, which is no
VLAN at all.

Currently 802.1Q FIDs are emulated in mlxsw driver using 802.1D FIDs. Using
unified bridge model, there is a FID->VID mapping, so it is possible to
stop emulating 802.1Q FIDs.

The main changes are:
1. Use 'SFGC.bridge_type' = 0, to separate between 802.1Q FIDs and
   802.1D FIDs.
2. Use VLAN RIF instead of the emulated one (VLAN_EMU which is emulated
   using FID RIF).
3. Create VID->FID mapping when the FID is created. Then when a new port
   is mapped to the FID, if it not in virtual mode, no new mapping is
   needed. Save the new port in 'port_vid_list', to be able to update a
   RIF in all {Port, VID}->FID mappings in case that the port will be in
   virtual mode later.
4. Add a dedicated operation function per FID family to update RIF for
   VID->FID mappings. For 802.1d and rFID families, just return. For
   802.1q family, handle the global mapping which is created for new 802.1q
   FID.
Signed-off-by: default avatarAmit Cohen <amcohen@nvidia.com>
Reviewed-by: default avatarPetr Machata <petrm@nvidia.com>
Signed-off-by: default avatarIdo Schimmel <idosch@nvidia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d4324e31
......@@ -94,6 +94,8 @@ struct mlxsw_sp_fid_ops {
void (*nve_flood_index_clear)(struct mlxsw_sp_fid *fid);
void (*fdb_clear_offload)(const struct mlxsw_sp_fid *fid,
const struct net_device *nve_dev);
int (*vid_to_fid_rif_update)(const struct mlxsw_sp_fid *fid,
const struct mlxsw_sp_rif *rif);
};
struct mlxsw_sp_fid_family {
......@@ -433,9 +435,14 @@ u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid)
static void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg)
{
struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
u16 vid = *(u16 *) arg;
mlxsw_sp_fid_8021q_fid(fid)->vid = vid;
if (mlxsw_sp->ubridge)
fid->fid_offset = fid->fid_index - fid->fid_family->start_index;
else
fid->fid_offset = 0;
}
......@@ -532,6 +539,35 @@ static int mlxsw_sp_fid_vni_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
return mlxsw_sp_fid_vni_to_fid_map(fid, rif, fid->vni_valid);
}
static int
mlxsw_sp_fid_vid_to_fid_map(const struct mlxsw_sp_fid *fid, u16 vid, bool valid,
const struct mlxsw_sp_rif *rif)
{
struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
char svfa_pl[MLXSW_REG_SVFA_LEN];
bool irif_valid;
u16 irif_index;
irif_valid = !!rif;
irif_index = rif ? mlxsw_sp_rif_index(rif) : 0;
mlxsw_reg_svfa_vid_pack(svfa_pl, valid, fid->fid_index, vid, irif_valid,
irif_index);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
}
static int
mlxsw_sp_fid_8021q_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
const struct mlxsw_sp_rif *rif)
{
struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
/* Update the global VID => FID mapping we created when the FID was
* configured.
*/
return mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, true, rif);
}
static int
mlxsw_sp_fid_port_vid_to_fid_rif_update_one(const struct mlxsw_sp_fid *fid,
struct mlxsw_sp_fid_port_vid *pv,
......@@ -555,6 +591,10 @@ static int mlxsw_sp_fid_vid_to_fid_rif_set(const struct mlxsw_sp_fid *fid,
u16 irif_index;
int err;
err = fid->fid_family->ops->vid_to_fid_rif_update(fid, rif);
if (err)
return err;
irif_index = mlxsw_sp_rif_index(rif);
list_for_each_entry(pv, &fid->port_vid_list, list) {
......@@ -582,6 +622,7 @@ static int mlxsw_sp_fid_vid_to_fid_rif_set(const struct mlxsw_sp_fid *fid,
mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv, false, 0);
}
fid->fid_family->ops->vid_to_fid_rif_update(fid, NULL);
return err;
}
......@@ -599,6 +640,8 @@ static void mlxsw_sp_fid_vid_to_fid_rif_unset(const struct mlxsw_sp_fid *fid)
mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv, false, 0);
}
fid->fid_family->ops->vid_to_fid_rif_update(fid, NULL);
}
static int mlxsw_sp_fid_reiv_handle(struct mlxsw_sp_fid *fid, u16 rif_index,
......@@ -1078,6 +1121,13 @@ mlxsw_sp_fid_8021d_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
br_fdb_clear_offload(nve_dev, 0);
}
static int
mlxsw_sp_fid_8021d_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
const struct mlxsw_sp_rif *rif)
{
return 0;
}
static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = {
.setup = mlxsw_sp_fid_8021d_setup,
.configure = mlxsw_sp_fid_8021d_configure,
......@@ -1092,6 +1142,7 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = {
.nve_flood_index_set = mlxsw_sp_fid_8021d_nve_flood_index_set,
.nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear,
.fdb_clear_offload = mlxsw_sp_fid_8021d_fdb_clear_offload,
.vid_to_fid_rif_update = mlxsw_sp_fid_8021d_vid_to_fid_rif_update,
};
#define MLXSW_SP_FID_8021Q_MAX (VLAN_N_VID - 2)
......@@ -1341,6 +1392,13 @@ static void mlxsw_sp_fid_rfid_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
WARN_ON_ONCE(1);
}
static int
mlxsw_sp_fid_rfid_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
const struct mlxsw_sp_rif *rif)
{
return 0;
}
static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = {
.setup = mlxsw_sp_fid_rfid_setup,
.configure = mlxsw_sp_fid_rfid_configure,
......@@ -1353,6 +1411,7 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = {
.vni_clear = mlxsw_sp_fid_rfid_vni_clear,
.nve_flood_index_set = mlxsw_sp_fid_rfid_nve_flood_index_set,
.nve_flood_index_clear = mlxsw_sp_fid_rfid_nve_flood_index_clear,
.vid_to_fid_rif_update = mlxsw_sp_fid_rfid_vid_to_fid_rif_update,
};
#define MLXSW_SP_RFID_BASE (15 * 1024)
......@@ -1437,6 +1496,103 @@ static const struct mlxsw_sp_fid_family mlxsw_sp_fid_dummy_family = {
.ops = &mlxsw_sp_fid_dummy_ops,
};
static int mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid *fid)
{
struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
int err;
err = mlxsw_sp_fid_op(fid, true);
if (err)
return err;
err = mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, true, fid->rif);
if (err)
goto err_vid_to_fid_map;
return 0;
err_vid_to_fid_map:
mlxsw_sp_fid_op(fid, false);
return err;
}
static void mlxsw_sp_fid_8021q_deconfigure(struct mlxsw_sp_fid *fid)
{
struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
if (fid->vni_valid)
mlxsw_sp_nve_fid_disable(fid->fid_family->mlxsw_sp, fid);
mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, false, NULL);
mlxsw_sp_fid_op(fid, false);
}
static int mlxsw_sp_fid_8021q_port_vid_map(struct mlxsw_sp_fid *fid,
struct mlxsw_sp_port *mlxsw_sp_port,
u16 vid)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
u8 local_port = mlxsw_sp_port->local_port;
int err;
/* In case there are no {Port, VID} => FID mappings on the port,
* we can use the global VID => FID mapping we created when the
* FID was configured, otherwise, configure new mapping.
*/
if (mlxsw_sp->fid_core->port_fid_mappings[local_port]) {
err = __mlxsw_sp_fid_port_vid_map(fid, local_port, vid, true);
if (err)
return err;
}
err = mlxsw_sp_fid_evid_map(fid, local_port, vid, true);
if (err)
goto err_fid_evid_map;
err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port,
vid);
if (err)
goto err_port_vid_list_add;
return 0;
err_port_vid_list_add:
mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
err_fid_evid_map:
if (mlxsw_sp->fid_core->port_fid_mappings[local_port])
__mlxsw_sp_fid_port_vid_map(fid, local_port, vid, false);
return err;
}
static void
mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid *fid,
struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
u8 local_port = mlxsw_sp_port->local_port;
mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
if (mlxsw_sp->fid_core->port_fid_mappings[local_port])
__mlxsw_sp_fid_port_vid_map(fid, local_port, vid, false);
}
static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops = {
.setup = mlxsw_sp_fid_8021q_setup,
.configure = mlxsw_sp_fid_8021q_configure,
.deconfigure = mlxsw_sp_fid_8021q_deconfigure,
.index_alloc = mlxsw_sp_fid_8021d_index_alloc,
.compare = mlxsw_sp_fid_8021q_compare,
.port_vid_map = mlxsw_sp_fid_8021q_port_vid_map,
.port_vid_unmap = mlxsw_sp_fid_8021q_port_vid_unmap,
.vni_set = mlxsw_sp_fid_8021d_vni_set,
.vni_clear = mlxsw_sp_fid_8021d_vni_clear,
.nve_flood_index_set = mlxsw_sp_fid_8021d_nve_flood_index_set,
.nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear,
.fdb_clear_offload = mlxsw_sp_fid_8021q_fdb_clear_offload,
.vid_to_fid_rif_update = mlxsw_sp_fid_8021q_vid_to_fid_rif_update,
};
/* There are 4K-2 802.1Q FIDs */
#define MLXSW_SP_FID_8021Q_UB_START 1 /* FID 0 is reserved. */
#define MLXSW_SP_FID_8021Q_UB_END (MLXSW_SP_FID_8021Q_UB_START + \
......@@ -1455,6 +1611,22 @@ static const struct mlxsw_sp_fid_family mlxsw_sp_fid_dummy_family = {
#define MLXSW_SP_RFID_UB_END (MLXSW_SP_RFID_UB_START + \
MLXSW_SP_FID_RFID_UB_MAX - 1)
static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021q_ub_family = {
.type = MLXSW_SP_FID_TYPE_8021Q_UB,
.fid_size = sizeof(struct mlxsw_sp_fid_8021q),
.start_index = MLXSW_SP_FID_8021Q_UB_START,
.end_index = MLXSW_SP_FID_8021Q_UB_END,
.flood_tables = mlxsw_sp_fid_8021d_ub_flood_tables,
.nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_ub_flood_tables),
.rif_type = MLXSW_SP_RIF_TYPE_VLAN,
.ops = &mlxsw_sp_fid_8021q_ops,
.flood_rsp = false,
.bridge_type = MLXSW_REG_BRIDGE_TYPE_0,
.pgt_base = MLXSW_SP_FID_8021Q_PGT_BASE,
.smpe_index_valid = false,
.ubridge = true,
};
static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021d_ub_family = {
.type = MLXSW_SP_FID_TYPE_8021D_UB,
.fid_size = sizeof(struct mlxsw_sp_fid_8021d),
......@@ -1498,11 +1670,28 @@ const struct mlxsw_sp_fid_family *mlxsw_sp1_fid_family_arr[] = {
[MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family,
[MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp_fid_dummy_family,
[MLXSW_SP_FID_TYPE_8021Q_UB] = &mlxsw_sp1_fid_8021q_ub_family,
[MLXSW_SP_FID_TYPE_8021D_UB] = &mlxsw_sp1_fid_8021d_ub_family,
[MLXSW_SP_FID_TYPE_DUMMY_UB] = &mlxsw_sp1_fid_dummy_ub_family,
[MLXSW_SP_FID_TYPE_RFID_UB] = &mlxsw_sp_fid_rfid_ub_family,
};
static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021q_ub_family = {
.type = MLXSW_SP_FID_TYPE_8021Q_UB,
.fid_size = sizeof(struct mlxsw_sp_fid_8021q),
.start_index = MLXSW_SP_FID_8021Q_UB_START,
.end_index = MLXSW_SP_FID_8021Q_UB_END,
.flood_tables = mlxsw_sp_fid_8021d_ub_flood_tables,
.nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_ub_flood_tables),
.rif_type = MLXSW_SP_RIF_TYPE_VLAN,
.ops = &mlxsw_sp_fid_8021q_ops,
.flood_rsp = false,
.bridge_type = MLXSW_REG_BRIDGE_TYPE_0,
.pgt_base = MLXSW_SP_FID_8021Q_PGT_BASE,
.smpe_index_valid = true,
.ubridge = true,
};
static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021d_ub_family = {
.type = MLXSW_SP_FID_TYPE_8021D_UB,
.fid_size = sizeof(struct mlxsw_sp_fid_8021d),
......@@ -1534,6 +1723,7 @@ const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr[] = {
[MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family,
[MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp_fid_dummy_family,
[MLXSW_SP_FID_TYPE_8021Q_UB] = &mlxsw_sp2_fid_8021q_ub_family,
[MLXSW_SP_FID_TYPE_8021D_UB] = &mlxsw_sp2_fid_8021d_ub_family,
[MLXSW_SP_FID_TYPE_DUMMY_UB] = &mlxsw_sp2_fid_dummy_ub_family,
[MLXSW_SP_FID_TYPE_RFID_UB] = &mlxsw_sp_fid_rfid_ub_family,
......
......@@ -7730,7 +7730,8 @@ u16 mlxsw_sp_rif_vid(struct mlxsw_sp *mlxsw_sp, const struct net_device *dev)
/* We only return the VID for VLAN RIFs. Otherwise we return an
* invalid value (0).
*/
if (rif->ops->type != MLXSW_SP_RIF_TYPE_VLAN_EMU)
if (rif->ops->type != MLXSW_SP_RIF_TYPE_VLAN_EMU &&
rif->ops->type != MLXSW_SP_RIF_TYPE_VLAN)
goto out;
vid = mlxsw_sp_fid_8021q_vid(rif->fid);
......
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