#include <linux/list.h>
 #include <linux/notifier.h>
 #include <linux/dcbnl.h>
+#include <linux/inetdevice.h>
 #include <net/switchdev.h>
 #include <generated/utsrelease.h>
 
        return mlxsw_sp_port_dev_addr_set(mlxsw_sp_port, addr);
 }
 
-static int mlxsw_sp_port_stp_state_set(struct mlxsw_sp_port *mlxsw_sp_port,
-                                      u16 vid, enum mlxsw_reg_spms_state state)
-{
-       struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
-       char *spms_pl;
-       int err;
-
-       spms_pl = kmalloc(MLXSW_REG_SPMS_LEN, GFP_KERNEL);
-       if (!spms_pl)
-               return -ENOMEM;
-       mlxsw_reg_spms_pack(spms_pl, mlxsw_sp_port->local_port);
-       mlxsw_reg_spms_vid_pack(spms_pl, vid, state);
-       err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spms), spms_pl);
-       kfree(spms_pl);
-       return err;
-}
-
 static int mlxsw_sp_port_mtu_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 mtu)
 {
        struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
        return 0;
 }
 
-static struct mlxsw_sp_fid *
-mlxsw_sp_vfid_find(const struct mlxsw_sp *mlxsw_sp, u16 vid)
-{
-       struct mlxsw_sp_fid *f;
-
-       list_for_each_entry(f, &mlxsw_sp->port_vfids.list, list) {
-               if (f->vid == vid)
-                       return f;
-       }
-
-       return NULL;
-}
-
-static u16 mlxsw_sp_avail_vfid_get(const struct mlxsw_sp *mlxsw_sp)
-{
-       return find_first_zero_bit(mlxsw_sp->port_vfids.mapped,
-                                  MLXSW_SP_VFID_PORT_MAX);
-}
-
-static int mlxsw_sp_vfid_op(struct mlxsw_sp *mlxsw_sp, u16 fid, bool create)
-{
-       char sfmr_pl[MLXSW_REG_SFMR_LEN];
-
-       mlxsw_reg_sfmr_pack(sfmr_pl, !create, fid, 0);
-       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
-}
-
-static void mlxsw_sp_vport_vfid_leave(struct mlxsw_sp_port *mlxsw_sp_vport);
-
-static struct mlxsw_sp_fid *mlxsw_sp_vfid_create(struct mlxsw_sp *mlxsw_sp,
-                                                u16 vid)
-{
-       struct device *dev = mlxsw_sp->bus_info->dev;
-       struct mlxsw_sp_fid *f;
-       u16 vfid, fid;
-       int err;
-
-       vfid = mlxsw_sp_avail_vfid_get(mlxsw_sp);
-       if (vfid == MLXSW_SP_VFID_PORT_MAX) {
-               dev_err(dev, "No available vFIDs\n");
-               return ERR_PTR(-ERANGE);
-       }
-
-       fid = mlxsw_sp_vfid_to_fid(vfid);
-       err = mlxsw_sp_vfid_op(mlxsw_sp, fid, true);
-       if (err) {
-               dev_err(dev, "Failed to create FID=%d\n", fid);
-               return ERR_PTR(err);
-       }
-
-       f = kzalloc(sizeof(*f), GFP_KERNEL);
-       if (!f)
-               goto err_allocate_vfid;
-
-       f->leave = mlxsw_sp_vport_vfid_leave;
-       f->fid = fid;
-       f->vid = vid;
-
-       list_add(&f->list, &mlxsw_sp->port_vfids.list);
-       set_bit(vfid, mlxsw_sp->port_vfids.mapped);
-
-       return f;
-
-err_allocate_vfid:
-       mlxsw_sp_vfid_op(mlxsw_sp, fid, false);
-       return ERR_PTR(-ENOMEM);
-}
-
-static void mlxsw_sp_vfid_destroy(struct mlxsw_sp *mlxsw_sp,
-                                 struct mlxsw_sp_fid *f)
-{
-       u16 vfid = mlxsw_sp_fid_to_vfid(f->fid);
-
-       clear_bit(vfid, mlxsw_sp->port_vfids.mapped);
-       list_del(&f->list);
-
-       mlxsw_sp_vfid_op(mlxsw_sp, f->fid, false);
-
-       kfree(f);
-}
-
 static struct mlxsw_sp_port *
 mlxsw_sp_port_vport_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
 {
        kfree(mlxsw_sp_vport);
 }
 
-static int mlxsw_sp_vport_fid_map(struct mlxsw_sp_port *mlxsw_sp_vport, u16 fid,
-                                 bool valid)
-{
-       enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID;
-       u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport);
-
-       return mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_vport, mt, valid, fid,
-                                           vid);
-}
-
-static int mlxsw_sp_vport_vfid_join(struct mlxsw_sp_port *mlxsw_sp_vport)
-{
-       u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport);
-       struct mlxsw_sp_fid *f;
-       int err;
-
-       f = mlxsw_sp_vfid_find(mlxsw_sp_vport->mlxsw_sp, vid);
-       if (!f) {
-               f = mlxsw_sp_vfid_create(mlxsw_sp_vport->mlxsw_sp, vid);
-               if (IS_ERR(f))
-                       return PTR_ERR(f);
-       }
-
-       if (!f->ref_count) {
-               err = mlxsw_sp_vport_flood_set(mlxsw_sp_vport, f->fid, true);
-               if (err)
-                       goto err_vport_flood_set;
-       }
-
-       err = mlxsw_sp_vport_fid_map(mlxsw_sp_vport, f->fid, true);
-       if (err)
-               goto err_vport_fid_map;
-
-       mlxsw_sp_vport_fid_set(mlxsw_sp_vport, f);
-       f->ref_count++;
-
-       return 0;
-
-err_vport_fid_map:
-       if (!f->ref_count)
-               mlxsw_sp_vport_flood_set(mlxsw_sp_vport, f->fid, false);
-err_vport_flood_set:
-       if (!f->ref_count)
-               mlxsw_sp_vfid_destroy(mlxsw_sp_vport->mlxsw_sp, f);
-       return err;
-}
-
-static void mlxsw_sp_vport_vfid_leave(struct mlxsw_sp_port *mlxsw_sp_vport)
-{
-       struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport);
-
-       mlxsw_sp_vport_fid_set(mlxsw_sp_vport, NULL);
-
-       mlxsw_sp_vport_fid_map(mlxsw_sp_vport, f->fid, false);
-
-       if (--f->ref_count == 0) {
-               mlxsw_sp_vport_flood_set(mlxsw_sp_vport, f->fid, false);
-               mlxsw_sp_vfid_destroy(mlxsw_sp_vport->mlxsw_sp, f);
-       }
-}
-
 int mlxsw_sp_port_add_vid(struct net_device *dev, __be16 __always_unused proto,
                          u16 vid)
 {
                }
        }
 
-       err = mlxsw_sp_vport_vfid_join(mlxsw_sp_vport);
-       if (err) {
-               netdev_err(dev, "Failed to join vFID\n");
-               goto err_vport_vfid_join;
-       }
-
        err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_vport, vid, false);
        if (err) {
                netdev_err(dev, "Failed to disable learning for VID=%d\n", vid);
                goto err_port_add_vid;
        }
 
-       err = mlxsw_sp_port_stp_state_set(mlxsw_sp_vport, vid,
-                                         MLXSW_REG_SPMS_STATE_FORWARDING);
-       if (err) {
-               netdev_err(dev, "Failed to set STP state for VID=%d\n", vid);
-               goto err_port_stp_state_set;
-       }
-
        return 0;
 
-err_port_stp_state_set:
-       mlxsw_sp_port_vlan_set(mlxsw_sp_vport, vid, vid, false, false);
 err_port_add_vid:
        mlxsw_sp_port_vid_learning_set(mlxsw_sp_vport, vid, true);
 err_port_vid_learning_set:
-       mlxsw_sp_vport_vfid_leave(mlxsw_sp_vport);
-err_vport_vfid_join:
        if (list_is_singular(&mlxsw_sp_port->vports_list))
                mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
 err_port_vp_mode_trans:
                return 0;
        }
 
-       err = mlxsw_sp_port_stp_state_set(mlxsw_sp_vport, vid,
-                                         MLXSW_REG_SPMS_STATE_DISCARDING);
-       if (err) {
-               netdev_err(dev, "Failed to set STP state for VID=%d\n", vid);
-               return err;
-       }
-
        err = mlxsw_sp_port_vlan_set(mlxsw_sp_vport, vid, vid, false, false);
        if (err) {
                netdev_err(dev, "Failed to set VLAN membership for VID=%d\n",
        mlxsw_sp->core = mlxsw_core;
        mlxsw_sp->bus_info = mlxsw_bus_info;
        INIT_LIST_HEAD(&mlxsw_sp->fids);
-       INIT_LIST_HEAD(&mlxsw_sp->port_vfids.list);
        INIT_LIST_HEAD(&mlxsw_sp->br_vfids.list);
        INIT_LIST_HEAD(&mlxsw_sp->br_mids.list);
 
        dev_put(mlxsw_sp_port->dev);
 }
 
+static bool mlxsw_sp_rif_should_config(struct mlxsw_sp_rif *r,
+                                      unsigned long event)
+{
+       switch (event) {
+       case NETDEV_UP:
+               if (!r)
+                       return true;
+               r->ref_count++;
+               return false;
+       case NETDEV_DOWN:
+               if (r && --r->ref_count == 0)
+                       return true;
+               /* It is possible we already removed the RIF ourselves
+                * if it was assigned to a netdev that is now a bridge
+                * or LAG slave.
+                */
+               return false;
+       }
+
+       return false;
+}
+
+static int mlxsw_sp_avail_rif_get(struct mlxsw_sp *mlxsw_sp)
+{
+       int i;
+
+       for (i = 0; i < MLXSW_SP_RIF_MAX; i++)
+               if (!mlxsw_sp->rifs[i])
+                       return i;
+
+       return MLXSW_SP_RIF_MAX;
+}
+
+static void mlxsw_sp_vport_rif_sp_attr_get(struct mlxsw_sp_port *mlxsw_sp_vport,
+                                          bool *p_lagged, u16 *p_system_port)
+{
+       u8 local_port = mlxsw_sp_vport->local_port;
+
+       *p_lagged = mlxsw_sp_vport->lagged;
+       *p_system_port = *p_lagged ? mlxsw_sp_vport->lag_id : local_port;
+}
+
+static int mlxsw_sp_vport_rif_sp_op(struct mlxsw_sp_port *mlxsw_sp_vport,
+                                   struct net_device *l3_dev, u16 rif,
+                                   bool create)
+{
+       struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp;
+       bool lagged = mlxsw_sp_vport->lagged;
+       char ritr_pl[MLXSW_REG_RITR_LEN];
+       u16 system_port;
+
+       mlxsw_reg_ritr_pack(ritr_pl, create, MLXSW_REG_RITR_SP_IF, rif,
+                           l3_dev->mtu, l3_dev->dev_addr);
+
+       mlxsw_sp_vport_rif_sp_attr_get(mlxsw_sp_vport, &lagged, &system_port);
+       mlxsw_reg_ritr_sp_if_pack(ritr_pl, lagged, system_port,
+                                 mlxsw_sp_vport_vid_get(mlxsw_sp_vport));
+
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
+}
+
+static void mlxsw_sp_vport_rif_sp_leave(struct mlxsw_sp_port *mlxsw_sp_vport);
+
+static struct mlxsw_sp_fid *
+mlxsw_sp_rfid_alloc(u16 fid, struct net_device *l3_dev)
+{
+       struct mlxsw_sp_fid *f;
+
+       f = kzalloc(sizeof(*f), GFP_KERNEL);
+       if (!f)
+               return NULL;
+
+       f->leave = mlxsw_sp_vport_rif_sp_leave;
+       f->ref_count = 0;
+       f->dev = l3_dev;
+       f->fid = fid;
+
+       return f;
+}
+
+static struct mlxsw_sp_rif *
+mlxsw_sp_rif_alloc(u16 rif, struct net_device *l3_dev, struct mlxsw_sp_fid *f)
+{
+       struct mlxsw_sp_rif *r;
+
+       r = kzalloc(sizeof(*r), GFP_KERNEL);
+       if (!r)
+               return NULL;
+
+       ether_addr_copy(r->addr, l3_dev->dev_addr);
+       r->mtu = l3_dev->mtu;
+       r->ref_count = 1;
+       r->dev = l3_dev;
+       r->rif = rif;
+       r->f = f;
+
+       return r;
+}
+
+static struct mlxsw_sp_rif *
+mlxsw_sp_vport_rif_sp_create(struct mlxsw_sp_port *mlxsw_sp_vport,
+                            struct net_device *l3_dev)
+{
+       struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp;
+       struct mlxsw_sp_fid *f;
+       struct mlxsw_sp_rif *r;
+       u16 fid, rif;
+       int err;
+
+       rif = mlxsw_sp_avail_rif_get(mlxsw_sp);
+       if (rif == MLXSW_SP_RIF_MAX)
+               return ERR_PTR(-ERANGE);
+
+       err = mlxsw_sp_vport_rif_sp_op(mlxsw_sp_vport, l3_dev, rif, true);
+       if (err)
+               return ERR_PTR(err);
+
+       fid = mlxsw_sp_rif_sp_to_fid(rif);
+       err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, true);
+       if (err)
+               goto err_rif_fdb_op;
+
+       f = mlxsw_sp_rfid_alloc(fid, l3_dev);
+       if (!f) {
+               err = -ENOMEM;
+               goto err_rfid_alloc;
+       }
+
+       r = mlxsw_sp_rif_alloc(rif, l3_dev, f);
+       if (!r) {
+               err = -ENOMEM;
+               goto err_rif_alloc;
+       }
+
+       f->r = r;
+       mlxsw_sp->rifs[rif] = r;
+
+       return r;
+
+err_rif_alloc:
+       kfree(f);
+err_rfid_alloc:
+       mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, false);
+err_rif_fdb_op:
+       mlxsw_sp_vport_rif_sp_op(mlxsw_sp_vport, l3_dev, rif, false);
+       return ERR_PTR(err);
+}
+
+static void mlxsw_sp_vport_rif_sp_destroy(struct mlxsw_sp_port *mlxsw_sp_vport,
+                                         struct mlxsw_sp_rif *r)
+{
+       struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp;
+       struct net_device *l3_dev = r->dev;
+       struct mlxsw_sp_fid *f = r->f;
+       u16 fid = f->fid;
+       u16 rif = r->rif;
+
+       mlxsw_sp->rifs[rif] = NULL;
+       f->r = NULL;
+
+       kfree(r);
+
+       kfree(f);
+
+       mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, false);
+
+       mlxsw_sp_vport_rif_sp_op(mlxsw_sp_vport, l3_dev, rif, false);
+}
+
+static int mlxsw_sp_vport_rif_sp_join(struct mlxsw_sp_port *mlxsw_sp_vport,
+                                     struct net_device *l3_dev)
+{
+       struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp;
+       struct mlxsw_sp_rif *r;
+
+       r = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
+       if (!r) {
+               r = mlxsw_sp_vport_rif_sp_create(mlxsw_sp_vport, l3_dev);
+               if (IS_ERR(r))
+                       return PTR_ERR(r);
+       }
+
+       mlxsw_sp_vport_fid_set(mlxsw_sp_vport, r->f);
+       r->f->ref_count++;
+
+       netdev_dbg(mlxsw_sp_vport->dev, "Joined FID=%d\n", r->f->fid);
+
+       return 0;
+}
+
+static void mlxsw_sp_vport_rif_sp_leave(struct mlxsw_sp_port *mlxsw_sp_vport)
+{
+       struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport);
+
+       netdev_dbg(mlxsw_sp_vport->dev, "Left FID=%d\n", f->fid);
+
+       mlxsw_sp_vport_fid_set(mlxsw_sp_vport, NULL);
+       if (--f->ref_count == 0)
+               mlxsw_sp_vport_rif_sp_destroy(mlxsw_sp_vport, f->r);
+}
+
+static int mlxsw_sp_inetaddr_vport_event(struct net_device *l3_dev,
+                                        struct net_device *port_dev,
+                                        unsigned long event, u16 vid)
+{
+       struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(port_dev);
+       struct mlxsw_sp_port *mlxsw_sp_vport;
+
+       mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, vid);
+       if (WARN_ON(!mlxsw_sp_vport))
+               return -EINVAL;
+
+       switch (event) {
+       case NETDEV_UP:
+               return mlxsw_sp_vport_rif_sp_join(mlxsw_sp_vport, l3_dev);
+       case NETDEV_DOWN:
+               mlxsw_sp_vport_rif_sp_leave(mlxsw_sp_vport);
+               break;
+       }
+
+       return 0;
+}
+
+static int mlxsw_sp_inetaddr_port_event(struct net_device *port_dev,
+                                       unsigned long event)
+{
+       if (netif_is_bridge_port(port_dev) || netif_is_lag_port(port_dev))
+               return 0;
+
+       return mlxsw_sp_inetaddr_vport_event(port_dev, port_dev, event, 1);
+}
+
+static int __mlxsw_sp_inetaddr_lag_event(struct net_device *l3_dev,
+                                        struct net_device *lag_dev,
+                                        unsigned long event, u16 vid)
+{
+       struct net_device *port_dev;
+       struct list_head *iter;
+       int err;
+
+       netdev_for_each_lower_dev(lag_dev, port_dev, iter) {
+               if (mlxsw_sp_port_dev_check(port_dev)) {
+                       err = mlxsw_sp_inetaddr_vport_event(l3_dev, port_dev,
+                                                           event, vid);
+                       if (err)
+                               return err;
+               }
+       }
+
+       return 0;
+}
+
+static int mlxsw_sp_inetaddr_lag_event(struct net_device *lag_dev,
+                                      unsigned long event)
+{
+       if (netif_is_bridge_port(lag_dev))
+               return 0;
+
+       return __mlxsw_sp_inetaddr_lag_event(lag_dev, lag_dev, event, 1);
+}
+
+static int mlxsw_sp_inetaddr_vlan_event(struct net_device *vlan_dev,
+                                       unsigned long event)
+{
+       struct net_device *real_dev = vlan_dev_real_dev(vlan_dev);
+       u16 vid = vlan_dev_vlan_id(vlan_dev);
+
+       if (mlxsw_sp_port_dev_check(real_dev))
+               return mlxsw_sp_inetaddr_vport_event(vlan_dev, real_dev, event,
+                                                    vid);
+       else if (netif_is_lag_master(real_dev))
+               return __mlxsw_sp_inetaddr_lag_event(vlan_dev, real_dev, event,
+                                                    vid);
+
+       return 0;
+}
+
+static int mlxsw_sp_inetaddr_event(struct notifier_block *unused,
+                                  unsigned long event, void *ptr)
+{
+       struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
+       struct net_device *dev = ifa->ifa_dev->dev;
+       struct mlxsw_sp *mlxsw_sp;
+       struct mlxsw_sp_rif *r;
+       int err = 0;
+
+       mlxsw_sp = mlxsw_sp_lower_get(dev);
+       if (!mlxsw_sp)
+               goto out;
+
+       r = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
+       if (!mlxsw_sp_rif_should_config(r, event))
+               goto out;
+
+       if (mlxsw_sp_port_dev_check(dev))
+               err = mlxsw_sp_inetaddr_port_event(dev, event);
+       else if (netif_is_lag_master(dev))
+               err = mlxsw_sp_inetaddr_lag_event(dev, event);
+       else if (is_vlan_dev(dev))
+               err = mlxsw_sp_inetaddr_vlan_event(dev, event);
+
+out:
+       return notifier_from_errno(err);
+}
+
 static int mlxsw_sp_rif_edit(struct mlxsw_sp *mlxsw_sp, u16 rif,
                             const char *mac, int mtu)
 {
        return NULL;
 }
 
-static u16 mlxsw_sp_vfid_to_br_vfid(u16 vfid)
+static u16 mlxsw_sp_avail_br_vfid_get(const struct mlxsw_sp *mlxsw_sp)
 {
-       return vfid - MLXSW_SP_VFID_PORT_MAX;
+       return find_first_zero_bit(mlxsw_sp->br_vfids.mapped,
+                                  MLXSW_SP_VFID_MAX);
 }
 
-static u16 mlxsw_sp_br_vfid_to_vfid(u16 br_vfid)
+static int mlxsw_sp_vfid_op(struct mlxsw_sp *mlxsw_sp, u16 fid, bool create)
 {
-       return MLXSW_SP_VFID_PORT_MAX + br_vfid;
-}
+       char sfmr_pl[MLXSW_REG_SFMR_LEN];
 
-static u16 mlxsw_sp_avail_br_vfid_get(const struct mlxsw_sp *mlxsw_sp)
-{
-       return find_first_zero_bit(mlxsw_sp->br_vfids.mapped,
-                                  MLXSW_SP_VFID_BR_MAX);
+       mlxsw_reg_sfmr_pack(sfmr_pl, !create, fid, 0);
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
 }
 
 static void mlxsw_sp_vport_br_vfid_leave(struct mlxsw_sp_port *mlxsw_sp_vport);
        u16 vfid, fid;
        int err;
 
-       vfid = mlxsw_sp_br_vfid_to_vfid(mlxsw_sp_avail_br_vfid_get(mlxsw_sp));
+       vfid = mlxsw_sp_avail_br_vfid_get(mlxsw_sp);
        if (vfid == MLXSW_SP_VFID_MAX) {
                dev_err(dev, "No available vFIDs\n");
                return ERR_PTR(-ERANGE);
        f->dev = br_dev;
 
        list_add(&f->list, &mlxsw_sp->br_vfids.list);
-       set_bit(mlxsw_sp_vfid_to_br_vfid(vfid), mlxsw_sp->br_vfids.mapped);
+       set_bit(vfid, mlxsw_sp->br_vfids.mapped);
 
        return f;
 
                                     struct mlxsw_sp_fid *f)
 {
        u16 vfid = mlxsw_sp_fid_to_vfid(f->fid);
-       u16 br_vfid = mlxsw_sp_vfid_to_br_vfid(vfid);
 
-       clear_bit(br_vfid, mlxsw_sp->br_vfids.mapped);
+       clear_bit(vfid, mlxsw_sp->br_vfids.mapped);
        list_del(&f->list);
 
        mlxsw_sp_vfid_op(mlxsw_sp, f->fid, false);
        kfree(f);
 }
 
+static int mlxsw_sp_vport_fid_map(struct mlxsw_sp_port *mlxsw_sp_vport, u16 fid,
+                                 bool valid)
+{
+       enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID;
+       u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport);
+
+       return mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_vport, mt, valid, fid,
+                                           vid);
+}
+
 static int mlxsw_sp_vport_br_vfid_join(struct mlxsw_sp_port *mlxsw_sp_vport,
                                       struct net_device *br_dev)
 {
 static int mlxsw_sp_vport_bridge_join(struct mlxsw_sp_port *mlxsw_sp_vport,
                                      struct net_device *br_dev)
 {
+       struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport);
        u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport);
        struct net_device *dev = mlxsw_sp_vport->dev;
        int err;
 
-       mlxsw_sp_vport_vfid_leave(mlxsw_sp_vport);
+       if (f && !WARN_ON(!f->leave))
+               f->leave(mlxsw_sp_vport);
 
        err = mlxsw_sp_vport_br_vfid_join(mlxsw_sp_vport, br_dev);
        if (err) {
                netdev_err(dev, "Failed to join vFID\n");
-               goto err_vport_br_vfid_join;
+               return err;
        }
 
        err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_vport, vid, true);
 
 err_port_vid_learning_set:
        mlxsw_sp_vport_br_vfid_leave(mlxsw_sp_vport);
-err_vport_br_vfid_join:
-       mlxsw_sp_vport_vfid_join(mlxsw_sp_vport);
        return err;
 }
 
 
        mlxsw_sp_vport_br_vfid_leave(mlxsw_sp_vport);
 
-       mlxsw_sp_vport_vfid_join(mlxsw_sp_vport);
-
-       mlxsw_sp_port_stp_state_set(mlxsw_sp_vport, vid,
-                                   MLXSW_REG_SPMS_STATE_FORWARDING);
-
        mlxsw_sp_vport->learning = 0;
        mlxsw_sp_vport->learning_sync = 0;
        mlxsw_sp_vport->uc_flood = 0;
        .notifier_call = mlxsw_sp_netdevice_event,
 };
 
+static struct notifier_block mlxsw_sp_inetaddr_nb __read_mostly = {
+       .notifier_call = mlxsw_sp_inetaddr_event,
+       .priority = 10, /* Must be called before FIB notifier block */
+};
+
 static int __init mlxsw_sp_module_init(void)
 {
        int err;
 
        register_netdevice_notifier(&mlxsw_sp_netdevice_nb);
+       register_inetaddr_notifier(&mlxsw_sp_inetaddr_nb);
        err = mlxsw_core_driver_register(&mlxsw_sp_driver);
        if (err)
                goto err_core_driver_register;
 static void __exit mlxsw_sp_module_exit(void)
 {
        mlxsw_core_driver_unregister(&mlxsw_sp_driver);
+       unregister_inetaddr_notifier(&mlxsw_sp_inetaddr_nb);
        unregister_netdevice_notifier(&mlxsw_sp_netdevice_nb);
 }