Index: trunk/src/VBox/Main/src-server/HostImpl.cpp
===================================================================
--- trunk/src/VBox/Main/src-server/HostImpl.cpp	(revision 43387)
+++ trunk/src/VBox/Main/src-server/HostImpl.cpp	(revision 43445)
@@ -179,4 +179,6 @@
     VirtualBox              *pParent;
 
+    HostNetworkInterfaceList llNetIfs;                  // list of network interfaces
+
 #ifdef VBOX_WITH_USB
     USBDeviceFilterList     llChildren;                 // all USB device filters
@@ -272,4 +274,6 @@
     registerMetrics(aParent->performanceCollector());
 #endif /* VBOX_WITH_RESOURCE_USAGE_API */
+    /* Create the list of network interfaces so their metrics get registered. */
+    updateNetIfList();
 
 #if defined (RT_OS_WINDOWS)
@@ -437,6 +441,11 @@
 
 #ifdef VBOX_WITH_RESOURCE_USAGE_API
-    unregisterMetrics (m->pParent->performanceCollector());
+    PerformanceCollector *aCollector = m->pParent->performanceCollector();
+    unregisterMetrics (aCollector);
+    HostNetworkInterfaceList::iterator it;
+    for (it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it)
+        (*it)->unregisterMetrics(aCollector, this);
 #endif /* VBOX_WITH_RESOURCE_USAGE_API */
+    m->llNetIfs.clear();
 
 #ifdef VBOX_WITH_USB
@@ -584,13 +593,19 @@
     if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+# ifdef VBOX_WITH_HOSTNETIF_API
+    int rc = updateNetIfList();
+    if (rc)
+    {
+        Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
+    }
+
+    SafeIfaceArray<IHostNetworkInterface> networkInterfaces (m->llNetIfs);
+    networkInterfaces.detachTo(ComSafeArrayOutArg(aNetworkInterfaces));
+
+    return S_OK;
+
+# else
     std::list<ComObjPtr<HostNetworkInterface> > list;
-
-# ifdef VBOX_WITH_HOSTNETIF_API
-    int rc = NetIfList(list);
-    if (rc)
-    {
-        Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
-    }
-# else
 
 #  if defined(RT_OS_DARWIN)
@@ -739,11 +754,4 @@
     }
 #  endif /* RT_OS_LINUX */
-# endif
-
-    std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
-    for (it = list.begin(); it != list.end(); ++it)
-    {
-        (*it)->setVirtualBox(m->pParent);
-    }
 
     SafeIfaceArray<IHostNetworkInterface> networkInterfaces (list);
@@ -752,4 +760,5 @@
     return S_OK;
 
+# endif
 #else
     /* Not implemented / supported on this platform. */
@@ -1391,8 +1400,9 @@
         return E_POINTER;
 
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
     *networkInterface = NULL;
     ComObjPtr<HostNetworkInterface> found;
-    std::list <ComObjPtr<HostNetworkInterface> > list;
-    int rc = NetIfList(list);
+    int rc = updateNetIfList();
     if (RT_FAILURE(rc))
     {
@@ -1400,6 +1410,6 @@
         return E_FAIL;
     }
-    std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
-    for (it = list.begin(); it != list.end(); ++it)
+    HostNetworkInterfaceList::iterator it;
+    for (it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it)
     {
         Bstr n;
@@ -1412,6 +1422,4 @@
         return setError(E_INVALIDARG,
                         HostNetworkInterface::tr("The host network interface with the given name could not be found"));
-
-    found->setVirtualBox(m->pParent);
 
     return found.queryInterfaceTo(networkInterface);
@@ -1429,8 +1437,9 @@
         return E_POINTER;
 
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
     *networkInterface = NULL;
     ComObjPtr<HostNetworkInterface> found;
-    std::list <ComObjPtr<HostNetworkInterface> > list;
-    int rc = NetIfList(list);
+    int rc = updateNetIfList();
     if (RT_FAILURE(rc))
     {
@@ -1438,6 +1447,6 @@
         return E_FAIL;
     }
-    std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
-    for (it = list.begin(); it != list.end(); ++it)
+    HostNetworkInterfaceList::iterator it;
+    for (it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it)
     {
         Bstr g;
@@ -1451,6 +1460,4 @@
                         HostNetworkInterface::tr("The host network interface with the given GUID could not be found"));
 
-    found->setVirtualBox(m->pParent);
-
     return found.queryInterfaceTo(networkInterface);
 #endif
@@ -1461,13 +1468,14 @@
 {
 #ifdef VBOX_WITH_HOSTNETIF_API
-    std::list <ComObjPtr<HostNetworkInterface> > allList;
-    int rc = NetIfList(allList);
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    int rc = updateNetIfList();
     if (RT_FAILURE(rc))
         return E_FAIL;
 
-    std::list <ComObjPtr<HostNetworkInterface> > resultList;
-
-    std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
-    for (it = allList.begin(); it != allList.end(); ++it)
+    HostNetworkInterfaceList resultList;
+
+    HostNetworkInterfaceList::iterator it;
+    for (it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it)
     {
         HostNetworkInterfaceType_T t;
@@ -1477,8 +1485,5 @@
 
         if (t == type)
-        {
-            (*it)->setVirtualBox(m->pParent);
             resultList.push_back (*it);
-        }
     }
 
@@ -2811,4 +2816,54 @@
 #endif /* VBOX_WITH_USB */
 
+HRESULT Host::updateNetIfList()
+{
+#ifdef VBOX_WITH_HOSTNETIF_API
+    AssertReturn(AutoCaller(this).state() == InInit ||
+                 isWriteLockOnCurrentThread(), E_FAIL);
+
+    HostNetworkInterfaceList list, listCopy;
+    int rc = NetIfList(list);
+    if (rc)
+    {
+        Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
+        return E_FAIL;
+    }
+    AssertReturn(m->pParent, E_FAIL);
+    /* Make a copy as the original may be partially destroyed later. */
+    listCopy = list;
+    HostNetworkInterfaceList::iterator itOld, itNew;
+    PerformanceCollector *aCollector = m->pParent->performanceCollector();
+    for (itOld = m->llNetIfs.begin(); itOld != m->llNetIfs.end(); ++itOld)
+    {
+        bool fGone = true;
+        Bstr nameOld;
+        (*itOld)->COMGETTER(Name) (nameOld.asOutParam());
+        for (itNew = listCopy.begin(); itNew != listCopy.end(); ++itNew)
+        {
+            Bstr nameNew;
+            (*itNew)->COMGETTER(Name) (nameNew.asOutParam());
+            if (nameNew == nameOld)
+            {
+                fGone = false;
+                listCopy.erase(itNew);
+                break;
+            }
+        }
+        if (fGone)
+            (*itOld)->unregisterMetrics(aCollector, this);
+    }
+    /* At this point listCopy will contain newly discovered interfaces only. */
+    for (itNew = listCopy.begin(); itNew != listCopy.end(); ++itNew)
+    {
+        (*itNew)->setVirtualBox(m->pParent);
+        (*itNew)->registerMetrics(aCollector, this);
+    }
+    m->llNetIfs = list;
+    return S_OK;
+#else
+    return E_NOTIMPL;
+#endif
+}
+
 #ifdef VBOX_WITH_RESOURCE_USAGE_API
 
@@ -2842,18 +2897,15 @@
 
     /* Create and register base metrics */
-    IUnknown *objptr;
-    ComObjPtr<Host> tmp = this;
-    tmp.queryInterfaceTo(&objptr);
-    pm::BaseMetric *cpuLoad = new pm::HostCpuLoadRaw(hal, objptr, cpuLoadUser, cpuLoadKernel,
+    pm::BaseMetric *cpuLoad = new pm::HostCpuLoadRaw(hal, this, cpuLoadUser, cpuLoadKernel,
                                           cpuLoadIdle);
     aCollector->registerBaseMetric (cpuLoad);
-    pm::BaseMetric *cpuMhz = new pm::HostCpuMhz(hal, objptr, cpuMhzSM);
+    pm::BaseMetric *cpuMhz = new pm::HostCpuMhz(hal, this, cpuMhzSM);
     aCollector->registerBaseMetric (cpuMhz);
-    pm::BaseMetric *ramUsage = new pm::HostRamUsage(hal, objptr,
+    pm::BaseMetric *ramUsage = new pm::HostRamUsage(hal, this,
                                                     ramUsageTotal,
                                                     ramUsageUsed,
                                                     ramUsageFree);
     aCollector->registerBaseMetric (ramUsage);
-    pm::BaseMetric *ramVmm = new pm::HostRamVmm(aCollector->getGuestManager(), objptr,
+    pm::BaseMetric *ramVmm = new pm::HostRamVmm(aCollector->getGuestManager(), this,
                                                 ramVMMUsed,
                                                 ramVMMFree,
Index: trunk/src/VBox/Main/src-server/HostNetworkInterfaceImpl.cpp
===================================================================
--- trunk/src/VBox/Main/src-server/HostNetworkInterfaceImpl.cpp	(revision 43387)
+++ trunk/src/VBox/Main/src-server/HostNetworkInterfaceImpl.cpp	(revision 43445)
@@ -22,4 +22,6 @@
 #include "Logging.h"
 #include "netif.h"
+#include "Performance.h"
+#include "PerformanceImpl.h"
 
 #include <iprt/cpp/utils.h>
@@ -83,4 +85,45 @@
 
     return S_OK;
+}
+
+void HostNetworkInterface::registerMetrics(PerformanceCollector *aCollector, ComPtr<IUnknown> objptr)
+{
+    LogFlowThisFunc(("mInterfaceName={%ls}, mGuid={%s}\n",
+                      mInterfaceName.raw(), mGuid.toString().c_str()));
+    pm::CollectorHAL *hal = aCollector->getHAL();
+    /* Create sub metrics */
+    Utf8StrFmt strName("Net/%ls/Load", mInterfaceName.raw());
+    pm::SubMetric *networkLoadRx   = new pm::SubMetric(strName + "/Rx",
+        "Percentage of network interface bandwidth used.");
+    pm::SubMetric *networkLoadTx   = new pm::SubMetric(strName + "/Tx",
+        "Percentage of network interface bandwidth used.");
+
+    /* Create and register base metrics */
+    pm::BaseMetric *networkLoad = new pm::HostNetworkLoadRaw(hal, objptr, strName, Utf8Str(mInterfaceName), networkLoadRx, networkLoadTx);
+    aCollector->registerBaseMetric(networkLoad);
+
+    aCollector->registerMetric(new pm::Metric(networkLoad, networkLoadRx, 0));
+    aCollector->registerMetric(new pm::Metric(networkLoad, networkLoadRx,
+                                              new pm::AggregateAvg()));
+    aCollector->registerMetric(new pm::Metric(networkLoad, networkLoadRx,
+                                              new pm::AggregateMin()));
+    aCollector->registerMetric(new pm::Metric(networkLoad, networkLoadRx,
+                                              new pm::AggregateMax()));
+
+    aCollector->registerMetric(new pm::Metric(networkLoad, networkLoadTx, 0));
+    aCollector->registerMetric(new pm::Metric(networkLoad, networkLoadTx,
+                                              new pm::AggregateAvg()));
+    aCollector->registerMetric(new pm::Metric(networkLoad, networkLoadTx,
+                                              new pm::AggregateMin()));
+    aCollector->registerMetric(new pm::Metric(networkLoad, networkLoadTx,
+                                              new pm::AggregateMax()));
+}
+
+void HostNetworkInterface::unregisterMetrics(PerformanceCollector *aCollector, ComPtr<IUnknown> objptr)
+{
+    LogFlowThisFunc(("mInterfaceName={%ls}, mGuid={%s}\n",
+                      mInterfaceName.raw(), mGuid.toString().c_str()));
+    aCollector->unregisterMetricsFor(objptr);
+    aCollector->unregisterBaseMetricsFor(objptr);
 }
 
@@ -553,4 +596,6 @@
     AutoCaller autoCaller(this);
     if (FAILED(autoCaller.rc())) return autoCaller.rc();
+    AssertReturn(mVBox != pVBox, S_OK);
+
     unconst(mVBox) = pVBox;
 
Index: trunk/src/VBox/Main/src-server/Performance.cpp
===================================================================
--- trunk/src/VBox/Main/src-server/Performance.cpp	(revision 43387)
+++ trunk/src/VBox/Main/src-server/Performance.cpp	(revision 43445)
@@ -55,4 +55,9 @@
 
 int CollectorHAL::getRawHostCpuLoad(uint64_t * /* user */, uint64_t * /* kernel */, uint64_t * /* idle */)
+{
+    return E_NOTIMPL;
+}
+
+int CollectorHAL::getRawHostNetworkLoad(const char * /* name */, uint64_t * /* rx */, uint64_t * /* tx */, uint64_t */* speed */)
 {
     return E_NOTIMPL;
@@ -554,5 +559,5 @@
     if (isEnabled())
     {
-        if (nowAt - mLastSampleTaken >= mPeriod * 1000)
+        if (mLastSampleTaken == 0)
         {
             mLastSampleTaken = nowAt;
@@ -561,4 +566,23 @@
             return true;
         }
+        /*
+         * We use low resolution timers which may fire just a little bit early.
+         * We compensate for that by jumping into the future by several
+         * milliseconds (see @bugref{6345}).
+         */
+        if (nowAt - mLastSampleTaken + PM_SAMPLER_PRECISION_MS >= mPeriod * 1000)
+        {
+            /*
+             * We don't want the beat to drift. This is why the timestamp of
+             * the last taken sample is not the actual time but the time we
+             * should have taken the measurement at.
+             */
+            mLastSampleTaken += mPeriod * 1000;
+            Log4(("{%p} " LOG_FN_FMT ": Collecting %s for obj(%p)...\n",
+                        this, __PRETTY_FUNCTION__, getName(), (void *)mObject));
+            return true;
+        }
+        Log4(("{%p} " LOG_FN_FMT ": Enabled but too early to collect %s for obj(%p)\n",
+              this, __PRETTY_FUNCTION__, getName(), (void *)mObject));
     }
     return false;
@@ -623,4 +647,47 @@
         mKernelPrev = kernel;
         mIdlePrev   = idle;
+    }
+}
+
+void HostNetworkLoadRaw::init(ULONG period, ULONG length)
+{
+    mPeriod = period;
+    mLength = length;
+    mRx->init(mLength);
+    mTx->init(mLength);
+    uint64_t speed;
+    int rc = mHAL->getRawHostNetworkLoad(mInterfaceName.c_str(), &mRxPrev, &mTxPrev, &speed);
+    AssertRC(rc);
+}
+
+void HostNetworkLoadRaw::preCollect(CollectorHints& /* hints */, uint64_t /* iTick */)
+{
+}
+
+void HostNetworkLoadRaw::collect()
+{
+    uint64_t rx, tx, speed;
+
+    int rc = mHAL->getRawHostNetworkLoad(mInterfaceName.c_str(), &rx, &tx, &speed);
+    if (RT_SUCCESS(rc))
+    {
+        uint64_t rxDiff = rx - mRxPrev;
+        uint64_t txDiff = tx - mTxPrev;
+
+        if (RT_UNLIKELY(speed * getPeriod() == 0))
+        {
+            Assert(speed * getPeriod());
+            LogFlowThisFunc(("Impossible! speed=%llu period=%d.\n", speed, getPeriod()));
+            mRx->put(0);
+            mTx->put(0);
+        }
+        else
+        {
+            mRx->put((ULONG)(PM_NETWORK_LOAD_MULTIPLIER * rxDiff / (speed * getPeriod())));
+            mTx->put((ULONG)(PM_NETWORK_LOAD_MULTIPLIER * txDiff / (speed * getPeriod())));
+        }
+
+        mRxPrev = rx;
+        mTxPrev = tx;
     }
 }
Index: trunk/src/VBox/Main/src-server/PerformanceImpl.cpp
===================================================================
--- trunk/src/VBox/Main/src-server/PerformanceImpl.cpp	(revision 43387)
+++ trunk/src/VBox/Main/src-server/PerformanceImpl.cpp	(revision 43445)
@@ -66,4 +66,12 @@
     "CPU/MHz:min",
     "CPU/MHz:max",
+    "Net/*/Load/Rx",
+    "Net/*/Load/Rx:avg",
+    "Net/*/Load/Rx:min",
+    "Net/*/Load/Rx:max",
+    "Net/*/Load/Tx",
+    "Net/*/Load/Tx:avg",
+    "Net/*/Load/Tx:min",
+    "Net/*/Load/Tx:max",
     "RAM/Usage/Total",
     "RAM/Usage/Total:avg",
Index: trunk/src/VBox/Main/src-server/linux/PerformanceLinux.cpp
===================================================================
--- trunk/src/VBox/Main/src-server/linux/PerformanceLinux.cpp	(revision 43387)
+++ trunk/src/VBox/Main/src-server/linux/PerformanceLinux.cpp	(revision 43445)
@@ -40,4 +40,5 @@
 
     virtual int getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle);
+    virtual int getRawHostNetworkLoad(const char *name, uint64_t *rx, uint64_t *tx, uint64_t *speed);
     virtual int getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total);
 private:
@@ -217,4 +218,50 @@
 }
 
-}
-
+int CollectorLinux::getRawHostNetworkLoad(const char *name, uint64_t *rx, uint64_t *tx, uint64_t *speed)
+{
+    int rc = VINF_SUCCESS;
+    char szIfName[/*IFNAMSIZ*/ 16 + 36];
+    long long unsigned int u64Rx, u64Tx, u64Speed;
+
+    RTStrPrintf(szIfName, sizeof(szIfName), "/sys/class/net/%s/statistics/rx_bytes", name);
+    FILE *f = fopen(szIfName, "r");
+    if (f)
+    {
+        if (fscanf(f, "%llu", &u64Rx) == 1)
+            *rx = u64Rx;
+        else
+            rc = VERR_FILE_IO_ERROR;
+        fclose(f);
+        RTStrPrintf(szIfName, sizeof(szIfName), "/sys/class/net/%s/statistics/tx_bytes", name);
+        f = fopen(szIfName, "r");
+        if (f)
+        {
+            if (fscanf(f, "%llu", &u64Tx) == 1)
+                *tx = u64Tx;
+            else
+                rc = VERR_FILE_IO_ERROR;
+            fclose(f);
+            RTStrPrintf(szIfName, sizeof(szIfName), "/sys/class/net/%s/speed", name);
+            f = fopen(szIfName, "r");
+            if (f)
+            {
+                if (fscanf(f, "%llu", &u64Speed) == 1)
+                    *speed = u64Speed * (1000000/8); /* Convert to bytes/sec */
+                else
+                    rc = VERR_FILE_IO_ERROR;
+                fclose(f);
+            }
+            else
+                rc = VERR_ACCESS_DENIED;
+        }
+        else
+            rc = VERR_ACCESS_DENIED;
+    }
+    else
+        rc = VERR_ACCESS_DENIED;
+
+    return rc;
+}
+
+}
+
