]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
spectrum: Reference count VLAN entries
authorIdo Schimmel <idosch@mellanox.com>
Wed, 28 Feb 2018 12:12:11 +0000 (13:12 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 30 May 2018 05:52:07 +0000 (07:52 +0200)
[ Upstream commit b3529af6bb0d4fe72defdd539712ceffaa054fb3 ]

One of the basic construct in the device is a port-VLAN pair, which can
be bound to a FID or a RIF in order to direct packets to the bridge or
the router, respectively.

Since not all the netdevs are configured with a VLAN (e.g., sw1p1 vs.
sw1p1.10), VID 1 is used to represent these and thus this VID can be
used by both upper devices of mlxsw ports and by the driver itself.

However, this VID is not reference counted and therefore might be freed
prematurely, which can result in various WARNINGs. For example:

$ ip link add name br0 type bridge vlan_filtering 1
$ teamd -t team0 -d -c '{"runner": {"name": "lacp"}}'
$ ip link set dev team0 master br0
$ ip link set dev enp1s0np1 master team0
$ ip address add 192.0.2.1/24 dev enp1s0np1

The enslavement to team0 will fail because team0 already has an upper
and thus vlan_vids_del_by_dev() will be executed as part of team's error
path which will delete VID 1 from enp1s0np1 (added by br0 as PVID). The
WARNING will be generated when the driver will realize it can't find VID
1 on the port and bind it to a RIF.

Fix this by adding a reference count to the VLAN entries on the port, in
a similar fashion to the reference counting used by the corresponding
'vlan_vid_info' structure in the 8021q driver.

Fixes: c57529e1d5d8 ("mlxsw: spectrum: Replace vPorts with Port-VLAN")
Reported-by: Tal Bar <talb@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Tested-by: Tal Bar <talb@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.h

index 99bd6e88ebc7e261933c512a723bf9f7a6d3cecd..8b48338b4a70e6e13eba24ea5875276a39754983 100644 (file)
@@ -1417,6 +1417,7 @@ mlxsw_sp_port_vlan_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
        }
 
        mlxsw_sp_port_vlan->mlxsw_sp_port = mlxsw_sp_port;
+       mlxsw_sp_port_vlan->ref_count = 1;
        mlxsw_sp_port_vlan->vid = vid;
        list_add(&mlxsw_sp_port_vlan->list, &mlxsw_sp_port->vlans_list);
 
@@ -1444,8 +1445,10 @@ mlxsw_sp_port_vlan_get(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
        struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
 
        mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
-       if (mlxsw_sp_port_vlan)
+       if (mlxsw_sp_port_vlan) {
+               mlxsw_sp_port_vlan->ref_count++;
                return mlxsw_sp_port_vlan;
+       }
 
        return mlxsw_sp_port_vlan_create(mlxsw_sp_port, vid);
 }
@@ -1454,6 +1457,9 @@ void mlxsw_sp_port_vlan_put(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
 {
        struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
 
+       if (--mlxsw_sp_port_vlan->ref_count != 0)
+               return;
+
        if (mlxsw_sp_port_vlan->bridge_port)
                mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan);
        else if (fid)
index 88892d47acaebf4df7a2b16c895ea604b8ef7ec3..8c4ce0a0cc825e93999f5130ede9f136052da35c 100644 (file)
@@ -194,6 +194,7 @@ struct mlxsw_sp_port_vlan {
        struct list_head list;
        struct mlxsw_sp_port *mlxsw_sp_port;
        struct mlxsw_sp_fid *fid;
+       unsigned int ref_count;
        u16 vid;
        struct mlxsw_sp_bridge_port *bridge_port;
        struct list_head bridge_vlan_node;