diff --git a/Ganeti/HTools/ExtLoader.hs b/Ganeti/HTools/ExtLoader.hs
index c244e1358b4b8387767ea953c347a061b0269a24..cc11b1c8bbda739ce7e0919fe0c7de68bdf6a67a 100644
--- a/Ganeti/HTools/ExtLoader.hs
+++ b/Ganeti/HTools/ExtLoader.hs
@@ -52,6 +52,7 @@ import qualified Ganeti.HTools.Node as Node
 
 import Ganeti.HTools.Types
 import Ganeti.HTools.CLI
+import Ganeti.HTools.Utils (sepSplit, tryRead)
 
 -- | Parse the environment and return the node\/instance names.
 --
@@ -66,6 +67,20 @@ parseEnv () = do
 wrapIO :: IO (Result a) -> IO (Result a)
 wrapIO = flip catch (return . Bad . show)
 
+parseUtilisation :: String -> Result (String, DynUtil)
+parseUtilisation line =
+    let columns = sepSplit ' ' line
+    in case columns of
+         [name, cpu, mem, dsk, net] -> do
+                      rcpu <- tryRead name cpu
+                      rmem <- tryRead name mem
+                      rdsk <- tryRead name dsk
+                      rnet <- tryRead name net
+                      let du = DynUtil { cpuWeight = rcpu, memWeight = rmem
+                                       , dskWeight = rdsk, netWeight = rnet }
+                      return (name, du)
+         _ -> Bad $ "Cannot parse line " ++ line
+
 -- | External tool data loader from a variety of sources.
 loadExternalData :: Options
                  -> IO (Node.List, Instance.List, String)
@@ -89,6 +104,16 @@ loadExternalData opts = do
                            " files options should be given.")
          exitWith $ ExitFailure 1
 
+  util_contents <- (case optDynuFile opts of
+                      Just path -> readFile path
+                      Nothing -> return "")
+  let util_data = mapM parseUtilisation $ lines util_contents
+  util_data' <- (case util_data of
+                   Ok x -> return x
+                   Bad y -> do
+                     hPutStrLn stderr ("Error: can't parse utilisation" ++
+                                       " data: " ++ show y)
+                     exitWith $ ExitFailure 1)
   input_data <-
       case () of
         _ | setRapi ->
@@ -101,7 +126,7 @@ loadExternalData opts = do
           | setSim -> Simu.loadData $ fromJust simdata
           | otherwise -> wrapIO $ Text.loadData nodef instf
 
-  let ldresult = input_data >>= Loader.mergeData
+  let ldresult = input_data >>= Loader.mergeData util_data'
   (loaded_nl, il, csf) <-
       (case ldresult of
          Ok x -> return x
diff --git a/Ganeti/HTools/IAlloc.hs b/Ganeti/HTools/IAlloc.hs
index 5063b9ab8798e5f92557f13d4d46ac409eda7ae1..af177f74b86c56de3ae246efe02afbfc18136231 100644
--- a/Ganeti/HTools/IAlloc.hs
+++ b/Ganeti/HTools/IAlloc.hs
@@ -110,7 +110,7 @@ parseData body = do
   let idata = fromJSObject ilist
   iobj <- mapM (\(x,y) -> asJSObject y >>= parseInstance ktn x) idata
   let (kti, il) = assignIndices iobj
-  (map_n, map_i, csf) <- mergeData (nl, il)
+  (map_n, map_i, csf) <- mergeData [] (nl, il)
   req_nodes <- fromObj "required_nodes" request
   optype <- fromObj "type" request
   rqtype <-
diff --git a/Ganeti/HTools/Loader.hs b/Ganeti/HTools/Loader.hs
index 8756f1a417f5fa2b164fb6f7199eff3647e27729..87f11f092a729f70b67241cdcda9cc8a5c991258 100644
--- a/Ganeti/HTools/Loader.hs
+++ b/Ganeti/HTools/Loader.hs
@@ -37,6 +37,7 @@ module Ganeti.HTools.Loader
     , Request(..)
     ) where
 
+import Control.Monad (foldM)
 import Data.Function (on)
 import Data.List
 import Data.Maybe (fromJust)
@@ -96,9 +97,9 @@ assocEqual = (==) `on` fst
 
 -- | For each instance, add its index to its primary and secondary nodes.
 fixNodes :: [(Ndx, Node.Node)]
-         -> (Idx, Instance.Instance)
+         -> Instance.Instance
          -> [(Ndx, Node.Node)]
-fixNodes accu (_, inst) =
+fixNodes accu inst =
     let
         pdx = Instance.pNode inst
         sdx = Instance.sNode inst
@@ -130,15 +131,21 @@ stripSuffix sflen name = take (length name - sflen) name
 
 -- | Initializer function that loads the data from a node and instance
 -- list and massages it into the correct format.
-mergeData :: (Node.AssocList,
+mergeData :: [(String, DynUtil)]  -- ^ Instance utilisation data
+          -> (Node.AssocList,
               Instance.AssocList) -- ^ Data from either Text.loadData
                                   -- or Rapi.loadData
           -> Result (Node.List, Instance.List, String)
-mergeData (nl, il) = do
-  let
-      nl2 = foldl' fixNodes nl il
-      il3 = Container.fromAssocList il
-      nl3 = Container.fromAssocList
+mergeData um (nl, il) = do
+  let il2 = Container.fromAssocList il
+  il3 <- foldM (\im (name, n_util) -> do
+                  idx <- Container.findByName im name
+                  let inst = Container.find idx im
+                      new_i = inst { Instance.util = n_util }
+                  return $ Container.add idx new_i im
+               ) il2 um
+  let nl2 = foldl' fixNodes nl (Container.elems il3)
+  let nl3 = Container.fromAssocList
             (map (\ (k, v) -> (k, Node.buildPeers v il3)) nl2)
       node_names = map Node.name $ Container.elems nl3
       inst_names = map Instance.name $ Container.elems il3
diff --git a/Ganeti/HTools/Node.hs b/Ganeti/HTools/Node.hs
index bc3210824977aa0147b5bbf742775e5194f8c42d..49d7b86c6b5ee23e673e0ec99598be4ede5f6be1 100644
--- a/Ganeti/HTools/Node.hs
+++ b/Ganeti/HTools/Node.hs
@@ -26,13 +26,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 -}
 
 module Ganeti.HTools.Node
-    ( Node(failN1, name, idx,
-           tMem, nMem, fMem, rMem, xMem,
-           tDsk, fDsk,
-           tCpu, uCpu,
-           pMem, pDsk, pRem, pCpu,
-           mDsk, mCpu, loDsk, hiCpu,
-           pList, sList, offline)
+    ( Node(..)
     , List
     -- * Constructor
     , create
@@ -217,16 +211,22 @@ buildPeers t il =
     in t {peers=pmap, failN1 = new_failN1, rMem = new_rmem, pRem = new_prem}
 
 -- | Assigns an instance to a node as primary and update the used VCPU
--- count.
+-- count and utilisation data.
 setPri :: Node -> Instance.Instance -> Node
-setPri t inst = t { pList = (Instance.idx inst):pList t
+setPri t inst = t { pList = Instance.idx inst:pList t
                   , uCpu = new_count
-                  , pCpu = fromIntegral new_count / tCpu t }
+                  , pCpu = fromIntegral new_count / tCpu t
+                  , utilLoad = utilLoad t `T.addUtil` Instance.util inst
+                  }
     where new_count = uCpu t + Instance.vcpus inst
 
 -- | Assigns an instance to a node as secondary without other updates.
 setSec :: Node -> Instance.Instance -> Node
-setSec t inst = t { sList = (Instance.idx inst):sList t }
+setSec t inst = t { sList = Instance.idx inst:sList t
+                  , utilLoad = old_load { T.dskWeight = T.dskWeight old_load +
+                                          T.dskWeight (Instance.util inst) }
+                  }
+    where old_load = utilLoad t
 
 -- * Update functions
 
@@ -250,9 +250,10 @@ removePri t inst =
         new_failn1 = new_mem <= rMem t
         new_ucpu = uCpu t - Instance.vcpus inst
         new_rcpu = fromIntegral new_ucpu / tCpu t
+        new_load = utilLoad t `T.subUtil` Instance.util inst
     in t {pList = new_plist, fMem = new_mem, fDsk = new_dsk,
           failN1 = new_failn1, pMem = new_mp, pDsk = new_dp,
-          uCpu = new_ucpu, pCpu = new_rcpu}
+          uCpu = new_ucpu, pCpu = new_rcpu, utilLoad = new_load}
 
 -- | Removes a secondary instance.
 removeSec :: Node -> Instance.Instance -> Node
@@ -273,9 +274,12 @@ removeSec t inst =
         new_prem = fromIntegral new_rmem / tMem t
         new_failn1 = fMem t <= new_rmem
         new_dp = fromIntegral new_dsk / tDsk t
+        old_load = utilLoad t
+        new_load = old_load { T.dskWeight = T.dskWeight old_load -
+                                            T.dskWeight (Instance.util inst) }
     in t {sList = new_slist, fDsk = new_dsk, peers = new_peers,
           failN1 = new_failn1, rMem = new_rmem, pDsk = new_dp,
-          pRem = new_prem}
+          pRem = new_prem, utilLoad = new_load}
 
 -- | Adds a primary instance.
 addPri :: Node -> Instance.Instance -> T.OpResult Node
@@ -288,6 +292,7 @@ addPri t inst =
         new_pcpu = fromIntegral new_ucpu / tCpu t
         new_dp = fromIntegral new_dsk / tDsk t
         l_cpu = mCpu t
+        new_load = utilLoad t `T.addUtil` Instance.util inst
     in if new_mem <= 0 then T.OpFail T.FailMem
        else if new_dsk <= 0 || mDsk t > new_dp then T.OpFail T.FailDisk
        else if new_failn1 && not (failN1 t) then T.OpFail T.FailMem
@@ -297,7 +302,7 @@ addPri t inst =
                new_mp = fromIntegral new_mem / tMem t
                r = t { pList = new_plist, fMem = new_mem, fDsk = new_dsk,
                        failN1 = new_failn1, pMem = new_mp, pDsk = new_dp,
-                       uCpu = new_ucpu, pCpu = new_pcpu }
+                       uCpu = new_ucpu, pCpu = new_pcpu, utilLoad = new_load }
            in T.OpGood r
 
 -- | Adds a secondary instance.
@@ -313,13 +318,16 @@ addSec t inst pdx =
         new_prem = fromIntegral new_rmem / tMem t
         new_failn1 = old_mem <= new_rmem
         new_dp = fromIntegral new_dsk / tDsk t
+        old_load = utilLoad t
+        new_load = old_load { T.dskWeight = T.dskWeight old_load +
+                                            T.dskWeight (Instance.util inst) }
     in if new_dsk <= 0 || mDsk t > new_dp then T.OpFail T.FailDisk
        else if new_failn1 && not (failN1 t) then T.OpFail T.FailMem
        else let new_slist = iname:sList t
                 r = t { sList = new_slist, fDsk = new_dsk,
                         peers = new_peers, failN1 = new_failn1,
                         rMem = new_rmem, pDsk = new_dp,
-                        pRem = new_prem }
+                        pRem = new_prem, utilLoad = new_load }
            in T.OpGood r
 
 -- * Stats functions
diff --git a/hbal.hs b/hbal.hs
index f3d2e584a243798a958b2708dccc936ff2e35835..aa5cfde750a0aa4f913b70d168fddb01f8b0f7f8 100644
--- a/hbal.hs
+++ b/hbal.hs
@@ -72,6 +72,7 @@ options =
     , oMaxCpu
     , oMinDisk
     , oDiskMoves
+    , oDynuFile
     , oShowVer
     , oShowHelp
     ]
diff --git a/hscan.hs b/hscan.hs
index 21d27aaa0656ec029fb95520c4685a667dcf2e1e..d4b86417b90ba88d486d6cc2880ec6e48126b756 100644
--- a/hscan.hs
+++ b/hscan.hs
@@ -135,7 +135,7 @@ main = do
               printf "%-*s " nlen name
               hFlush stdout
               input_data <- Rapi.loadData name
-              let ldresult = input_data >>= Loader.mergeData
+              let ldresult = input_data >>= Loader.mergeData []
               (case ldresult of
                  Bad err -> printf "\nError: failed to load data. \
                                    \Details:\n%s\n" err