mlxsw: spectrum: Introduce Port-VLAN structure
authorIdo Schimmel <idosch@mellanox.com>
Fri, 26 May 2017 06:37:26 +0000 (08:37 +0200)
committerDavid S. Miller <davem@davemloft.net>
Fri, 26 May 2017 19:18:45 +0000 (15:18 -0400)
This is the first step in the transition from the vPort model to a
unified Port-VLAN structure. The new structure is defined and created /
destroyed upon invocation of the 8021q ndos, but it's not actually used
throughout the code.

Subsequent patches will initialize it correctly and also create /
destroy it upon switchdev's VLAN object.

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>
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.h

index 5d673363154b430a4212d84e6fe92475b615b45d..6f5f01151c4948936e371a734ffd181efa500ea9 100644 (file)
@@ -1480,10 +1480,34 @@ static void mlxsw_sp_port_vport_destroy(struct mlxsw_sp_port *mlxsw_sp_vport)
        kfree(mlxsw_sp_vport);
 }
 
+static struct mlxsw_sp_port_vlan *
+mlxsw_sp_port_vlan_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
+{
+       struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
+
+       mlxsw_sp_port_vlan = kzalloc(sizeof(*mlxsw_sp_port_vlan), GFP_KERNEL);
+       if (!mlxsw_sp_port_vlan)
+               return ERR_PTR(-ENOMEM);
+
+       mlxsw_sp_port_vlan->mlxsw_sp_port = mlxsw_sp_port;
+       mlxsw_sp_port_vlan->vid = vid;
+       list_add(&mlxsw_sp_port_vlan->list, &mlxsw_sp_port->vlans_list);
+
+       return mlxsw_sp_port_vlan;
+}
+
+static void
+mlxsw_sp_port_vlan_destroy(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
+{
+       list_del(&mlxsw_sp_port_vlan->list);
+       kfree(mlxsw_sp_port_vlan);
+}
+
 static int mlxsw_sp_port_add_vid(struct net_device *dev,
                                 __be16 __always_unused proto, u16 vid)
 {
        struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
+       struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
        struct mlxsw_sp_port *mlxsw_sp_vport;
        bool untagged = vid == 1;
        int err;
@@ -1494,12 +1518,19 @@ static int mlxsw_sp_port_add_vid(struct net_device *dev,
        if (!vid)
                return 0;
 
-       if (mlxsw_sp_port_vport_find(mlxsw_sp_port, vid))
+       mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
+       if (mlxsw_sp_port_vlan)
                return 0;
 
+       mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_create(mlxsw_sp_port, vid);
+       if (IS_ERR(mlxsw_sp_port_vlan))
+               return PTR_ERR(mlxsw_sp_port_vlan);
+
        mlxsw_sp_vport = mlxsw_sp_port_vport_create(mlxsw_sp_port, vid);
-       if (!mlxsw_sp_vport)
-               return -ENOMEM;
+       if (!mlxsw_sp_vport) {
+               err = -ENOMEM;
+               goto err_port_vport_create;
+       }
 
        err = mlxsw_sp_port_vlan_set(mlxsw_sp_vport, vid, vid, true, untagged);
        if (err)
@@ -1509,6 +1540,8 @@ static int mlxsw_sp_port_add_vid(struct net_device *dev,
 
 err_port_add_vid:
        mlxsw_sp_port_vport_destroy(mlxsw_sp_vport);
+err_port_vport_create:
+       mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan);
        return err;
 }
 
@@ -1516,6 +1549,7 @@ static int mlxsw_sp_port_kill_vid(struct net_device *dev,
                                  __be16 __always_unused proto, u16 vid)
 {
        struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
+       struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
        struct mlxsw_sp_port *mlxsw_sp_vport;
        struct mlxsw_sp_fid *f;
 
@@ -1525,6 +1559,10 @@ static int mlxsw_sp_port_kill_vid(struct net_device *dev,
        if (!vid)
                return 0;
 
+       mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
+       if (WARN_ON(!mlxsw_sp_port_vlan))
+               return 0;
+
        mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, vid);
        if (WARN_ON(!mlxsw_sp_vport))
                return 0;
@@ -1540,6 +1578,8 @@ static int mlxsw_sp_port_kill_vid(struct net_device *dev,
 
        mlxsw_sp_port_vport_destroy(mlxsw_sp_vport);
 
+       mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan);
+
        return 0;
 }
 
@@ -2720,6 +2760,7 @@ static int __mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
                err = -ENOMEM;
                goto err_port_untagged_vlans_alloc;
        }
+       INIT_LIST_HEAD(&mlxsw_sp_port->vlans_list);
        INIT_LIST_HEAD(&mlxsw_sp_port->vports_list);
        INIT_LIST_HEAD(&mlxsw_sp_port->mall_tc_list);
 
@@ -2926,6 +2967,7 @@ static void __mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
        kfree(mlxsw_sp_port->untagged_vlans);
        kfree(mlxsw_sp_port->active_vlans);
        WARN_ON_ONCE(!list_empty(&mlxsw_sp_port->vports_list));
+       WARN_ON_ONCE(!list_empty(&mlxsw_sp_port->vlans_list));
        free_netdev(mlxsw_sp_port->dev);
 }
 
index 277a432af31969ce38aa3afdec5406b04509c15c..c4ac648f39bf77da52adf484d825c53a4c99bb3d 100644 (file)
@@ -203,6 +203,13 @@ struct mlxsw_sp_port_sample {
        bool truncate;
 };
 
+struct mlxsw_sp_port_vlan {
+       struct list_head list;
+       struct mlxsw_sp_port *mlxsw_sp_port;
+       struct mlxsw_sp_fid *fid;
+       u16 vid;
+};
+
 struct mlxsw_sp_port {
        struct net_device *dev;
        struct mlxsw_sp_port_pcpu_stats __percpu *pcpu_stats;
@@ -254,6 +261,7 @@ struct mlxsw_sp_port {
        } hw_stats;
        struct mlxsw_sp_port_sample *sample;
        unsigned int nr_port_vid_map;  /* {Port, VID} => FID mappings */
+       struct list_head vlans_list;
 };
 
 bool mlxsw_sp_port_dev_check(const struct net_device *dev);
@@ -279,6 +287,21 @@ mlxsw_sp_port_lagged_get(struct mlxsw_sp *mlxsw_sp, u16 lag_id, u8 port_index)
        return mlxsw_sp_port && mlxsw_sp_port->lagged ? mlxsw_sp_port : NULL;
 }
 
+static inline struct mlxsw_sp_port_vlan *
+mlxsw_sp_port_vlan_find_by_vid(const struct mlxsw_sp_port *mlxsw_sp_port,
+                              u16 vid)
+{
+       struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
+
+       list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list,
+                           list) {
+               if (mlxsw_sp_port_vlan->vid == vid)
+                       return mlxsw_sp_port_vlan;
+       }
+
+       return NULL;
+}
+
 static inline u16
 mlxsw_sp_vport_vid_get(const struct mlxsw_sp_port *mlxsw_sp_vport)
 {