mlxsw_sp = container_of(nb, struct mlxsw_sp, netdevice_nb);
        if (mlxsw_sp_netdev_is_ipip(mlxsw_sp, dev))
-               err = mlxsw_sp_netdevice_ipip_event(mlxsw_sp, dev, event);
+               err = mlxsw_sp_netdevice_ipip_event(mlxsw_sp, dev, event, ptr);
        else if (event == NETDEV_CHANGEADDR || event == NETDEV_CHANGEMTU)
                err = mlxsw_sp_netdevice_router_port_event(dev);
        else if (mlxsw_sp_is_vrf_event(event, ptr))
 
                mlxsw_sp_ipip_entry_demote_decap(mlxsw_sp, ipip_entry);
 }
 
+static int mlxsw_sp_netdevice_ipip_vrf_event(struct mlxsw_sp *mlxsw_sp,
+                                            struct net_device *ol_dev)
+{
+       struct mlxsw_sp_fib_entry *decap_fib_entry;
+       struct mlxsw_sp_ipip_entry *ipip_entry;
+       struct mlxsw_sp_rif_ipip_lb *lb_rif;
+
+       ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
+       if (!ipip_entry)
+               return 0;
+
+       /* When a tunneling device is moved to a different VRF, we need to
+        * update the backing loopback. Since RIFs can't be edited, we need to
+        * destroy and recreate it. That might create a window of opportunity
+        * where RALUE and RATR registers end up referencing a RIF that's
+        * already gone. RATRs are handled by the RIF destroy, and to take care
+        * of RALUE, demote the decap route back.
+        */
+       if (ipip_entry->decap_fib_entry)
+               mlxsw_sp_ipip_entry_demote_decap(mlxsw_sp, ipip_entry);
+
+       lb_rif = mlxsw_sp_ipip_ol_ipip_lb_create(mlxsw_sp, ipip_entry->ipipt,
+                                                ol_dev);
+       if (IS_ERR(lb_rif))
+               return PTR_ERR(lb_rif);
+       mlxsw_sp_rif_destroy(&ipip_entry->ol_lb->common);
+       ipip_entry->ol_lb = lb_rif;
+
+       if (ol_dev->flags & IFF_UP) {
+               decap_fib_entry = mlxsw_sp_ipip_entry_find_decap(mlxsw_sp,
+                                                                ipip_entry);
+               if (decap_fib_entry)
+                       mlxsw_sp_ipip_entry_promote_decap(mlxsw_sp, ipip_entry,
+                                                         decap_fib_entry);
+       }
+
+       return 0;
+}
+
 int mlxsw_sp_netdevice_ipip_event(struct mlxsw_sp *mlxsw_sp,
                                  struct net_device *ol_dev,
-                                 unsigned long event)
+                                 unsigned long event,
+                                 struct netdev_notifier_changeupper_info *info)
 {
        switch (event) {
        case NETDEV_REGISTER:
        case NETDEV_DOWN:
                mlxsw_sp_netdevice_ipip_down_event(mlxsw_sp, ol_dev);
                return 0;
+       case NETDEV_CHANGEUPPER:
+               if (netif_is_l3_master(info->upper_dev))
+                       return mlxsw_sp_netdevice_ipip_vrf_event(mlxsw_sp,
+                                                                ol_dev);
+               return 0;
        }
        return 0;
 }