PDMNetShaper.cpp revision c458503b85d643d51c5287959b8d96a3e32d9499
/* $Id$ */
/** @file
* PDM Network Shaper - Limit network traffic according to bandwidth
* group settings.
*/
/*
* Copyright (C) 2006-2012 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 *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_NET_SHAPER
#include "PDMInternal.h"
#ifdef VBOX_WITH_REM
#endif
#include <iprt/critsect.h>
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* Bandwidth group instance data
*/
typedef struct PDMNSBWGROUP
{
/** Pointer to the next group in the list. */
struct PDMNSBWGROUP *pNext;
/** Pointer to the shared UVM structure. */
struct PDMNETSHAPER *pShaper;
/** Critical section protecting all members below. */
/** Pointer to the first filter attached to this group. */
struct PDMNSFILTER *pFiltersHead;
/** Bandwidth group name. */
char *pszName;
/** Maximum number of bytes filters are allowed to transfer. */
volatile uint32_t cbTransferPerSecMax;
/** Number of bytes we are allowed to transfer in one burst. */
volatile uint32_t cbBucketSize;
/** Number of bytes we were allowed to transfer at the last update. */
volatile uint32_t cbTokensLast;
/** Timestamp of the last update */
volatile uint64_t tsUpdatedLast;
/** Reference counter - How many filters are associated with this group. */
} PDMNSBWGROUP;
/** Pointer to a bandwidth group. */
typedef PDMNSBWGROUP *PPDMNSBWGROUP;
/**
* 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;
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
{
if (RT_VALID_PTR(pcszId))
{
while ( pBwGroup
}
return pBwGroup;
}
{
}
#if 0
{
else
{
while ( pPrev
}
}
#endif
{
LogFlowFunc(("New rate limit is %d bytes per second, adjusted bucket size to %d bytes\n",
}
static int pdmNsBwGroupCreate(PPDMNETSHAPER pShaper, const char *pcszBwGroup, uint32_t cbTransferPerSecMax)
{
LogFlowFunc(("pShaper=%#p pcszBwGroup=%#p{%s} cbTransferPerSecMax=%u\n",
int rc;
if (!pBwGroup)
{
sizeof(PDMNSBWGROUP),
(void **)&pBwGroup);
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
{
;
LogFlowFunc(("pcszBwGroup={%s} cbBucketSize=%u\n",
return VINF_SUCCESS;
}
}
}
else
rc = VERR_NO_MEMORY;
}
else
return rc;
}
{
}
{
}
{
}
{
while (pFilter)
{
{
}
}
}
{
}
{
else
{
while ( pPrev
}
}
{
if (RT_SUCCESS(rc))
{
if (pcszBwGroup)
{
if (pBwGroupNew)
else
rc = VERR_NOT_FOUND;
}
if (RT_SUCCESS(rc))
{
if (pBwGroupOld)
}
}
return rc;
}
{
if (RT_SUCCESS(rc))
{
if (pBwGroup)
}
return rc;
}
{
return true;
bool fAllowed = true;
/* Re-fill the bucket first */
uint32_t uTokensAdded = (tsNow - pBwGroup->tsUpdatedLast)*pBwGroup->cbTransferPerSecMax/(1000*1000*1000);
if (cbTransfer > uTokens)
{
fAllowed = false;
}
else
{
}
return fAllowed;
}
VMMR3DECL(int) PDMR3NsBwGroupSetLimit(PVM pVM, const char *pcszBwGroup, uint32_t cbTransferPerSecMax)
{
if (RT_SUCCESS(rc))
{
if (pBwGroup)
{
/* Drop extra tokens */
}
}
return rc;
}
/**
* I/O thread for pending TX.
*
* @returns VINF_SUCCESS (ignored).
* @param pVM The VM handle.
* @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.
*/
{
sizeof(PDMNETSHAPER),
(void **)&pNetShaper);
if (RT_SUCCESS(rc))
{
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))
{
("Network shaper was already initialized\n"));
char szDesc[256];
static unsigned iThread;
if (RT_SUCCESS(rc))
{
return VINF_SUCCESS;
}
}
}
}
return rc;
}