bridge: try switchdev op first in __vlan_vid_add/del
authorJiri Pirko <jiri@mellanox.com>
Fri, 9 Oct 2015 11:54:11 +0000 (13:54 +0200)
committerDavid S. Miller <davem@davemloft.net>
Tue, 13 Oct 2015 02:35:20 +0000 (19:35 -0700)
Some drivers need to implement both switchdev vlan ops and
vid_add/kill ndos. For that to work in bridge code, we need to try
switchdev op first when adding/deleting vlan id.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Scott Feldman <sfeldma@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/bridge/br_vlan.c

index 7a95e31..ad7e4f6 100644 (file)
@@ -72,28 +72,20 @@ static void __vlan_add_flags(struct net_bridge_vlan *v, u16 flags)
 static int __vlan_vid_add(struct net_device *dev, struct net_bridge *br,
                          u16 vid, u16 flags)
 {
-       const struct net_device_ops *ops = dev->netdev_ops;
+       struct switchdev_obj_port_vlan v = {
+               .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN,
+               .flags = flags,
+               .vid_begin = vid,
+               .vid_end = vid,
+       };
        int err;
 
-       /* If driver uses VLAN ndo ops, use 8021q to install vid
-        * on device, otherwise try switchdev ops to install vid.
+       /* Try switchdev op first. In case it is not supported, fallback to
+        * 8021q add.
         */
-
-       if (ops->ndo_vlan_rx_add_vid) {
-               err = vlan_vid_add(dev, br->vlan_proto, vid);
-       } else {
-               struct switchdev_obj_port_vlan v = {
-                       .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN,
-                       .flags = flags,
-                       .vid_begin = vid,
-                       .vid_end = vid,
-               };
-
-               err = switchdev_port_obj_add(dev, &v.obj);
-               if (err == -EOPNOTSUPP)
-                       err = 0;
-       }
-
+       err = switchdev_port_obj_add(dev, &v.obj);
+       if (err == -EOPNOTSUPP)
+               return vlan_vid_add(dev, br->vlan_proto, vid);
        return err;
 }
 
@@ -122,27 +114,21 @@ static void __vlan_del_list(struct net_bridge_vlan *v)
 static int __vlan_vid_del(struct net_device *dev, struct net_bridge *br,
                          u16 vid)
 {
-       const struct net_device_ops *ops = dev->netdev_ops;
-       int err = 0;
+       struct switchdev_obj_port_vlan v = {
+               .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN,
+               .vid_begin = vid,
+               .vid_end = vid,
+       };
+       int err;
 
-       /* If driver uses VLAN ndo ops, use 8021q to delete vid
-        * on device, otherwise try switchdev ops to delete vid.
+       /* Try switchdev op first. In case it is not supported, fallback to
+        * 8021q del.
         */
-
-       if (ops->ndo_vlan_rx_kill_vid) {
+       err = switchdev_port_obj_del(dev, &v.obj);
+       if (err == -EOPNOTSUPP) {
                vlan_vid_del(dev, br->vlan_proto, vid);
-       } else {
-               struct switchdev_obj_port_vlan v = {
-                       .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN,
-                       .vid_begin = vid,
-                       .vid_end = vid,
-               };
-
-               err = switchdev_port_obj_del(dev, &v.obj);
-               if (err == -EOPNOTSUPP)
-                       err = 0;
+               return 0;
        }
-
        return err;
 }