aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIdo Schimmel <idosch@mellanox.com>2015-12-15 16:03:42 +0100
committerDavid S. Miller <davem@davemloft.net>2015-12-15 11:58:22 -0500
commitaac78a44088728f0712eaea74fbb2493e12080dd (patch)
tree1c3f35c84b52343972d1d2c688d20a472d7f96a0
parentmlxsw: spectrum: Adjust switchdev ops for VLAN devices (diff)
downloadlinux-dev-aac78a44088728f0712eaea74fbb2493e12080dd.tar.xz
linux-dev-aac78a44088728f0712eaea74fbb2493e12080dd.zip
mlxsw: spectrum: Adjust FDB notifications for VLAN devices
FDB notifications contain the FID and port (or LAG ID) on which the MAC was learned. In the case of the 802.1Q bridge one can easily derive the matching VID - as FID equals VID - and generate the appropriate notification for the software bridge. With VLAN devices this is no longer the case, as these are associated with a vFID. Solve that by converting the FID to a vFID and lookup the matching VLAN device. From that derive the VID and whether learning (and learning sync) should occur. 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>
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.h25
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c40
2 files changed, 61 insertions, 4 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index 809c32296aa6..33794f222614 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -73,6 +73,16 @@ static inline u16 mlxsw_sp_vfid_to_fid(u16 vfid)
return MLXSW_SP_VFID_BASE + vfid;
}
+static inline u16 mlxsw_sp_fid_to_vfid(u16 fid)
+{
+ return fid - MLXSW_SP_VFID_BASE;
+}
+
+static inline bool mlxsw_sp_fid_is_vfid(u16 fid)
+{
+ return fid >= MLXSW_SP_VFID_BASE;
+}
+
struct mlxsw_sp {
struct {
struct list_head list;
@@ -177,6 +187,21 @@ mlxsw_sp_port_vport_find(const struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
return NULL;
}
+static inline struct mlxsw_sp_port *
+mlxsw_sp_port_vport_find_by_vfid(const struct mlxsw_sp_port *mlxsw_sp_port,
+ u16 vfid)
+{
+ struct mlxsw_sp_port *mlxsw_sp_vport;
+
+ list_for_each_entry(mlxsw_sp_vport, &mlxsw_sp_port->vports_list,
+ vport.list) {
+ if (mlxsw_sp_vport_vfid_get(mlxsw_sp_vport) == vfid)
+ return mlxsw_sp_vport;
+ }
+
+ return NULL;
+}
+
enum mlxsw_sp_flood_table {
MLXSW_SP_FLOOD_TABLE_UC,
MLXSW_SP_FLOOD_TABLE_BM,
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
index 49d531873536..e6e5b5e17847 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
@@ -994,6 +994,24 @@ static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp,
return;
}
+ if (mlxsw_sp_fid_is_vfid(fid)) {
+ u16 vfid = mlxsw_sp_fid_to_vfid(fid);
+ struct mlxsw_sp_port *mlxsw_sp_vport;
+
+ mlxsw_sp_vport = mlxsw_sp_port_vport_find_by_vfid(mlxsw_sp_port,
+ vfid);
+ if (!mlxsw_sp_vport) {
+ netdev_err(mlxsw_sp_port->dev, "Failed to find a matching vPort following FDB notification\n");
+ return;
+ }
+
+ vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport);
+ /* Override the physical port with the vPort. */
+ mlxsw_sp_port = mlxsw_sp_vport;
+ } else {
+ vid = fid;
+ }
+
err = mlxsw_sp_port_fdb_uc_op(mlxsw_sp_port, mac, fid,
adding && mlxsw_sp_port->learning, true);
if (err) {
@@ -1002,8 +1020,6 @@ static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp,
return;
}
- vid = fid;
-
mlxsw_sp_fdb_call_notifiers(mlxsw_sp_port->learning,
mlxsw_sp_port->learning_sync,
adding, mac, vid, mlxsw_sp_port->dev);
@@ -1026,6 +1042,24 @@ static void mlxsw_sp_fdb_notify_mac_lag_process(struct mlxsw_sp *mlxsw_sp,
return;
}
+ if (mlxsw_sp_fid_is_vfid(fid)) {
+ u16 vfid = mlxsw_sp_fid_to_vfid(fid);
+ struct mlxsw_sp_port *mlxsw_sp_vport;
+
+ mlxsw_sp_vport = mlxsw_sp_port_vport_find_by_vfid(mlxsw_sp_port,
+ vfid);
+ if (!mlxsw_sp_vport) {
+ netdev_err(mlxsw_sp_port->dev, "Failed to find a matching vPort following FDB notification\n");
+ return;
+ }
+
+ vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport);
+ /* Override the physical port with the vPort. */
+ mlxsw_sp_port = mlxsw_sp_vport;
+ } else {
+ vid = fid;
+ }
+
err = mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp, lag_id, mac, fid,
adding && mlxsw_sp_port->learning,
true);
@@ -1035,8 +1069,6 @@ static void mlxsw_sp_fdb_notify_mac_lag_process(struct mlxsw_sp *mlxsw_sp,
return;
}
- vid = fid;
-
mlxsw_sp_fdb_call_notifiers(mlxsw_sp_port->learning,
mlxsw_sp_port->learning_sync,
adding, mac, vid,