#include <linux/netdevice.h>
 #include <linux/rtnetlink.h>
 #include <linux/slab.h>
+#include <net/switchdev.h>
 
 #include "br_private.h"
 
                clear_bit(vid, v->untagged_bitmap);
 }
 
+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;
+       int err;
+
+       /* If driver uses VLAN ndo ops, use 8021q to install vid
+        * on device, otherwise try switchdev ops to install vid.
+        */
+
+       if (ops->ndo_vlan_rx_add_vid) {
+               err = vlan_vid_add(dev, br->vlan_proto, vid);
+       } else {
+               struct switchdev_obj vlan_obj = {
+                       .id = SWITCHDEV_OBJ_PORT_VLAN,
+                       .u.vlan = {
+                               .flags = flags,
+                               .vid_start = vid,
+                               .vid_end = vid,
+                       },
+               };
+
+               err = switchdev_port_obj_add(dev, &vlan_obj);
+               if (err == -EOPNOTSUPP)
+                       err = 0;
+       }
+
+       return err;
+}
+
 static int __vlan_add(struct net_port_vlans *v, u16 vid, u16 flags)
 {
        struct net_bridge_port *p = NULL;
                 * This ensures tagged traffic enters the bridge when
                 * promiscuous mode is disabled by br_manage_promisc().
                 */
-               err = vlan_vid_add(dev, br->vlan_proto, vid);
+               err = __vlan_vid_add(dev, br, vid, flags);
                if (err)
                        return err;
        }
        return err;
 }
 
+static void __vlan_vid_del(struct net_device *dev, struct net_bridge *br,
+                          u16 vid)
+{
+       const struct net_device_ops *ops = dev->netdev_ops;
+
+       /* If driver uses VLAN ndo ops, use 8021q to delete vid
+        * on device, otherwise try switchdev ops to delete vid.
+        */
+
+       if (ops->ndo_vlan_rx_kill_vid) {
+               vlan_vid_del(dev, br->vlan_proto, vid);
+       } else {
+               struct switchdev_obj vlan_obj = {
+                       .id = SWITCHDEV_OBJ_PORT_VLAN,
+                       .u.vlan = {
+                               .vid_start = vid,
+                               .vid_end = vid,
+                       },
+               };
+
+               switchdev_port_obj_del(dev, &vlan_obj);
+       }
+}
+
 static int __vlan_del(struct net_port_vlans *v, u16 vid)
 {
        if (!test_bit(vid, v->vlan_bitmap))
 
        if (v->port_idx) {
                struct net_bridge_port *p = v->parent.port;
-               vlan_vid_del(p->dev, p->br->vlan_proto, vid);
+               __vlan_vid_del(p->dev, p->br, vid);
        }
 
        clear_bit(vid, v->vlan_bitmap);