/* $Id$ */
/** @file
* PDM Network Shaper - Limit network traffic according to bandwidth group settings.
*/
/*
* Copyright (C) 2011-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include "PDMInternal.h"
#ifdef VBOX_WITH_REM
#endif
#include <iprt/critsect.h>
#include "PDMNetShaperInternal.h"
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* Network shaper data. One instance per VM.
*/
typedef struct PDMNETSHAPER
{
/** Pointer to the VM. */
/** Critical section protecting all members below. */
/** Pending TX thread. */
/** Pointer to the first bandwidth group. */
} PDMNETSHAPER;
/** Takes the shaper lock (asserts but doesn't return or anything on
* failure). */
#define LOCK_NETSHAPER(a_pShaper) do { int rcShaper = RTCritSectEnter(&(a_pShaper)->Lock); AssertRC(rcShaper); } while (0)
/** Takes the shaper lock, returns + asserts on failure. */
do { int rcShaper = RTCritSectEnter(&(a_pShaper)->Lock); AssertRCReturn(rcShaper, rcShaper); } while (0)
/** Releases the shaper lock (asserts on failure). */
#define UNLOCK_NETSHAPER(a_pShaper) do { int rcShaper = RTCritSectLeave(&(a_pShaper)->Lock); AssertRC(rcShaper); } while (0)
{
if (RT_VALID_PTR(pszId))
{
while ( pBwGroup
}
return pBwGroup;
}
{
}
#if 0
{
else
{
while ( pPrev
}
}
#endif
{
pBwGroup->cbBucket = RT_MAX(PDM_NETSHAPER_MIN_BUCKET_SIZE, cbPerSecMax * PDM_NETSHAPER_MAX_LATENCY / 1000);
LogFlow(("pdmNsBwGroupSetLimit: New rate limit is %llu bytes per second, adjusted bucket size to %u bytes\n",
}
{
LogFlow(("pdmNsBwGroupCreate: pShaper=%#p pszBwGroup=%#p{%s} cbPerSecMax=%llu\n", pShaper, pszBwGroup, pszBwGroup, cbPerSecMax));
int rc;
if (!pBwGroup)
{
MM_TAG_PDM_NET_SHAPER, (void **)&pBwGroup);
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
{
LogFlowFunc(("pszBwGroup={%s} cbBucket=%u\n",
return VINF_SUCCESS;
}
}
}
else
rc = VERR_NO_MEMORY;
}
else
return rc;
}
{
}
{
}
{
}
{
/*
* We don't need to hold the bandwidth group lock to iterate over the list
* of filters since the filters are removed while the shaper lock is being
* held.
*/
//LOCK_NETSHAPER(pShaper);
/* Check if the group is disabled. */
if (pBwGroup->cbPerSecMax == 0)
return;
while (pFilter)
{
{
}
}
//UNLOCK_NETSHAPER(pShaper);
}
{
}
{
/*
* We need to make sure we hold the shaper lock since pdmNsBwGroupXmitPending()
* does not hold the bandwidth group lock while iterating over the list
* of group's filters.
*/
else
{
while ( pPrev
}
}
/**
* Attach network filter driver from bandwidth group.
*
* @returns VBox status code.
* @param pVM Handle of VM.
* @param pDrvIns The driver instance.
* @param pszBwGroup Name of the bandwidth group to attach to.
* @param pFilter Pointer to the filter we attach.
*/
VMMR3_INT_DECL(int) PDMR3NsAttach(PUVM pUVM, PPDMDRVINS pDrvIns, const char *pszBwGroup, PPDMNSFILTER pFilter)
{
if (pszBwGroup)
{
if (pBwGroupNew)
else
rc = VERR_NOT_FOUND;
}
if (RT_SUCCESS(rc))
{
if (pBwGroupOld)
}
return rc;
}
/**
* Detach network filter driver from bandwidth group.
*
* @returns VBox status code.
* @param pUVM The user mode VM handle.
* @param pDrvIns The driver instance.
* @param pFilter Pointer to the filter we detach.
*/
{
destructors are called on constructor failure. */
if (!pFilter->pBwGroupR3)
return VINF_SUCCESS;
if (pBwGroup)
return VINF_SUCCESS;
}
/**
* Adjusts the maximum rate for the bandwidth group.
*
* @returns VBox status code.
* @param pUVM The user mode VM handle.
* @param pszBwGroup Name of the bandwidth group to attach to.
* @param cbPerSecMax Maximum number of bytes per second to be transmitted.
*/
{
int rc;
if (pBwGroup)
{
if (RT_SUCCESS(rc))
{
/* Drop extra tokens */
}
}
else
rc = VERR_NOT_FOUND;
return rc;
}
/**
* I/O thread for pending TX.
*
* @returns VINF_SUCCESS (ignored).
* @param pVM Pointer to the VM.
* @param pThread The PDM thread data.
*/
{
{
while (pBwGroup)
{
}
}
return VINF_SUCCESS;
}
/**
* @copydoc FNPDMTHREADWAKEUPINT
*/
{
/* Nothing to do */
return VINF_SUCCESS;
}
/**
* Terminate the network shaper.
*
* @returns VBox error code.
* @param pVM Pointer to VM.
*
* @remarks This method destroys all bandwidth group objects.
*/
{
/* Destroy the bandwidth managers. */
while (pBwGroup)
{
}
return VINF_SUCCESS;
}
/**
* Initialize the network shaper.
*
* @returns VBox status code
* @param pVM Pointer to the VM.
*/
{
AssertMsgReturn(!pUVM->pdm.s.pNetShaper, ("Network shaper was already initialized\n"), VERR_WRONG_ORDER);
if (RT_SUCCESS(rc))
{
PCFGMNODE pCfgNetShaper = CFGMR3GetChild(CFGMR3GetChild(CFGMR3GetRoot(pVM), "PDM"), "NetworkShaper");
if (RT_SUCCESS(rc))
{
/* Create all bandwidth groups. */
if (pCfgBwGrp)
{
{
if (!pszBwGrpId)
{
rc = VERR_NO_MEMORY;
break;
}
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
if (RT_FAILURE(rc))
break;
}
}
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
return VINF_SUCCESS;
}
}
}
}
return rc;
}