PDMNetShaper.cpp revision 1e1273b11e17928ec3c3a8fff45121aa7a169413
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/* $Id$ */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** @file
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * PDM Network Shaper - Limit network traffic according to bandwidth group settings.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/*
c97989161fbe75bc14cea477a5443bbf474dd3advboxsync * Copyright (C) 2011-2013 Oracle Corporation
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * available from http://www.virtualbox.org. This file is free software;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * you can redistribute it and/or modify it under the terms of the GNU
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * General Public License (GPL) as published by the Free Software
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/*******************************************************************************
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync* Header Files *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync*******************************************************************************/
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define LOG_GROUP LOG_GROUP_NET_SHAPER
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include "PDMInternal.h"
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/vmm/pdm.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/vmm/mm.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef VBOX_WITH_REM
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync# include <VBox/vmm/rem.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/vmm/vm.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/vmm/uvm.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/err.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/log.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <iprt/asm.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <iprt/assert.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <iprt/thread.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <iprt/mem.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <iprt/critsect.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <iprt/tcp.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <iprt/path.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <iprt/string.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/vmm/pdmnetshaper.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include "PDMNetShaperInternal.h"
19b725c530eb49600728765de7ed451cbe290740vboxsync
19b725c530eb49600728765de7ed451cbe290740vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/*******************************************************************************
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync* Structures and Typedefs *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync*******************************************************************************/
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Network shaper data. One instance per VM.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsynctypedef struct PDMNETSHAPER
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Pointer to the VM. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PVM pVM;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Critical section protecting all members below. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTCRITSECT Lock;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Pending TX thread. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PPDMTHREAD pTxThread;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Pointer to the first bandwidth group. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PPDMNSBWGROUP pBwGroupsHead;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync} PDMNETSHAPER;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Takes the shaper lock (asserts but doesn't return or anything on
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * failure). */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define LOCK_NETSHAPER(a_pShaper) do { int rcShaper = RTCritSectEnter(&(a_pShaper)->Lock); AssertRC(rcShaper); } while (0)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Takes the shaper lock, returns + asserts on failure. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define LOCK_NETSHAPER_RETURN(a_pShaper) \
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync do { int rcShaper = RTCritSectEnter(&(a_pShaper)->Lock); AssertRCReturn(rcShaper, rcShaper); } while (0)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Releases the shaper lock (asserts on failure). */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define UNLOCK_NETSHAPER(a_pShaper) do { int rcShaper = RTCritSectLeave(&(a_pShaper)->Lock); AssertRC(rcShaper); } while (0)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic PPDMNSBWGROUP pdmNsBwGroupFindById(PPDMNETSHAPER pShaper, const char *pszId)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PPDMNSBWGROUP pBwGroup = NULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_VALID_PTR(pszId))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LOCK_NETSHAPER(pShaper);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pBwGroup = pShaper->pBwGroupsHead;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync while ( pBwGroup
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync && RTStrCmp(pBwGroup->pszNameR3, pszId))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pBwGroup = pBwGroup->pNextR3;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync UNLOCK_NETSHAPER(pShaper);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return pBwGroup;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic void pdmNsBwGroupLink(PPDMNSBWGROUP pBwGroup)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PPDMNETSHAPER pShaper = pBwGroup->pShaperR3;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LOCK_NETSHAPER(pShaper);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pBwGroup->pNextR3 = pShaper->pBwGroupsHead;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pShaper->pBwGroupsHead = pBwGroup;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync UNLOCK_NETSHAPER(pShaper);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#if 0
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic void pdmNsBwGroupUnlink(PPDMNSBWGROUP pBwGroup)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PPDMNETSHAPER pShaper = pBwGroup->pShaper;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LOCK_NETSHAPER(pShaper);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pBwGroup == pShaper->pBwGroupsHead)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pShaper->pBwGroupsHead = pBwGroup->pNext;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PPDMNSBWGROUP pPrev = pShaper->pBwGroupsHead;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync while ( pPrev
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync && pPrev->pNext != pBwGroup)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPrev = pPrev->pNext;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertPtr(pPrev);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPrev->pNext = pBwGroup->pNext;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync UNLOCK_NETSHAPER(pShaper);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic void pdmNsBwGroupSetLimit(PPDMNSBWGROUP pBwGroup, uint64_t cbPerSecMax)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pBwGroup->cbPerSecMax = cbPerSecMax;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pBwGroup->cbBucket = RT_MAX(PDM_NETSHAPER_MIN_BUCKET_SIZE, cbPerSecMax * PDM_NETSHAPER_MAX_LATENCY / 1000);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlow(("pdmNsBwGroupSetLimit: New rate limit is %llu bytes per second, adjusted bucket size to %u bytes\n",
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pBwGroup->cbPerSecMax, pBwGroup->cbBucket));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int pdmNsBwGroupCreate(PPDMNETSHAPER pShaper, const char *pszBwGroup, uint64_t cbPerSecMax)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlow(("pdmNsBwGroupCreate: pShaper=%#p pszBwGroup=%#p{%s} cbPerSecMax=%llu\n", pShaper, pszBwGroup, pszBwGroup, cbPerSecMax));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertPtrReturn(pShaper, VERR_INVALID_POINTER);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertPtrReturn(pszBwGroup, VERR_INVALID_POINTER);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertReturn(*pszBwGroup != '\0', VERR_INVALID_PARAMETER);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PPDMNSBWGROUP pBwGroup = pdmNsBwGroupFindById(pShaper, pszBwGroup);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (!pBwGroup)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = MMHyperAlloc(pShaper->pVM, sizeof(PDMNSBWGROUP), 64,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync MM_TAG_PDM_NET_SHAPER, (void **)&pBwGroup);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_SUCCESS(rc))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PDMR3CritSectInit(pShaper->pVM, &pBwGroup->Lock, RT_SRC_POS, "BWGRP");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_SUCCESS(rc))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pBwGroup->pszNameR3 = MMR3HeapStrDup(pShaper->pVM, MM_TAG_PDM_NET_SHAPER, pszBwGroup);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pBwGroup->pszNameR3)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pBwGroup->pShaperR3 = pShaper;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pBwGroup->cRefs = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pdmNsBwGroupSetLimit(pBwGroup, cbPerSecMax);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pBwGroup->cbTokensLast = pBwGroup->cbBucket;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pBwGroup->tsUpdatedLast = RTTimeSystemNanoTS();
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlowFunc(("pszBwGroup={%s} cbBucket=%u\n",
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pszBwGroup, pBwGroup->cbBucket));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pdmNsBwGroupLink(pBwGroup);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PDMR3CritSectDelete(&pBwGroup->Lock);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync MMHyperFree(pShaper->pVM, pBwGroup);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = VERR_NO_MEMORY;
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync }
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = VERR_ALREADY_EXISTS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlowFunc(("returns rc=%Rrc\n", rc));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return rc;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsyncstatic void pdmNsBwGroupTerminate(PPDMNSBWGROUP pBwGroup)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync Assert(pBwGroup->cRefs == 0);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (PDMCritSectIsInitialized(&pBwGroup->Lock))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PDMR3CritSectDelete(&pBwGroup->Lock);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncDECLINLINE(void) pdmNsBwGroupRef(PPDMNSBWGROUP pBwGroup)
19b725c530eb49600728765de7ed451cbe290740vboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASMAtomicIncU32(&pBwGroup->cRefs);
19b725c530eb49600728765de7ed451cbe290740vboxsync}
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncDECLINLINE(void) pdmNsBwGroupUnref(PPDMNSBWGROUP pBwGroup)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(pBwGroup->cRefs > 0);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASMAtomicDecU32(&pBwGroup->cRefs);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic void pdmNsBwGroupXmitPending(PPDMNSBWGROUP pBwGroup)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * We don't need to hold the bandwidth group lock to iterate over the list
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * of filters since the filters are removed while the shaper lock is being
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * held.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertPtr(pBwGroup);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertPtr(pBwGroup->pShaperR3);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(RTCritSectIsOwner(&pBwGroup->pShaperR3->Lock));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync //LOCK_NETSHAPER(pShaper);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Check if the group is disabled. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pBwGroup->cbPerSecMax == 0)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PPDMNSFILTER pFilter = pBwGroup->pFiltersHeadR3;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync while (pFilter)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync bool fChoked = ASMAtomicXchgBool(&pFilter->fChoked, false);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log3((LOG_FN_FMT ": pFilter=%#p fChoked=%RTbool\n", __PRETTY_FUNCTION__, pFilter, fChoked));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (fChoked && pFilter->pIDrvNetR3)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
19b725c530eb49600728765de7ed451cbe290740vboxsync LogFlowFunc(("Calling pfnXmitPending for pFilter=%#p\n", pFilter));
19b725c530eb49600728765de7ed451cbe290740vboxsync pFilter->pIDrvNetR3->pfnXmitPending(pFilter->pIDrvNetR3);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pFilter = pFilter->pNextR3;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync //UNLOCK_NETSHAPER(pShaper);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic void pdmNsFilterLink(PPDMNSFILTER pFilter)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PPDMNSBWGROUP pBwGroup = pFilter->pBwGroupR3;
19b725c530eb49600728765de7ed451cbe290740vboxsync int rc = PDMCritSectEnter(&pBwGroup->Lock, VERR_SEM_BUSY); AssertRC(rc);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pFilter->pNextR3 = pBwGroup->pFiltersHeadR3;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pBwGroup->pFiltersHeadR3 = pFilter;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PDMCritSectLeave(&pBwGroup->Lock); AssertRC(rc);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic void pdmNsFilterUnlink(PPDMNSFILTER pFilter)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PPDMNSBWGROUP pBwGroup = pFilter->pBwGroupR3;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * We need to make sure we hold the shaper lock since pdmNsBwGroupXmitPending()
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * does not hold the bandwidth group lock while iterating over the list
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * of group's filters.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertPtr(pBwGroup);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertPtr(pBwGroup->pShaperR3);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(RTCritSectIsOwner(&pBwGroup->pShaperR3->Lock));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc = PDMCritSectEnter(&pBwGroup->Lock, VERR_SEM_BUSY); AssertRC(rc);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pFilter == pBwGroup->pFiltersHeadR3)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pBwGroup->pFiltersHeadR3 = pFilter->pNextR3;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PPDMNSFILTER pPrev = pBwGroup->pFiltersHeadR3;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync while ( pPrev
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync && pPrev->pNextR3 != pFilter)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPrev = pPrev->pNextR3;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertPtr(pPrev);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPrev->pNextR3 = pFilter->pNextR3;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PDMCritSectLeave(&pBwGroup->Lock); AssertRC(rc);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Attach network filter driver from bandwidth group.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM Handle of VM.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pDrvIns The driver instance.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pszBwGroup Name of the bandwidth group to attach to.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pFilter Pointer to the filter we attach.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncVMMR3_INT_DECL(int) PDMR3NsAttach(PUVM pUVM, PPDMDRVINS pDrvIns, const char *pszBwGroup, PPDMNSFILTER pFilter)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync VM_ASSERT_EMT(pUVM->pVM);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertPtrReturn(pFilter, VERR_INVALID_POINTER);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertReturn(pFilter->pBwGroupR3 == NULL, VERR_ALREADY_EXISTS);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PPDMNETSHAPER pShaper = pUVM->pdm.s.pNetShaper;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LOCK_NETSHAPER_RETURN(pShaper);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc = VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PPDMNSBWGROUP pBwGroupNew = NULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pszBwGroup)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pBwGroupNew = pdmNsBwGroupFindById(pShaper, pszBwGroup);
19b725c530eb49600728765de7ed451cbe290740vboxsync if (pBwGroupNew)
19b725c530eb49600728765de7ed451cbe290740vboxsync pdmNsBwGroupRef(pBwGroupNew);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = VERR_NOT_FOUND;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_SUCCESS(rc))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PPDMNSBWGROUP pBwGroupOld = ASMAtomicXchgPtrT(&pFilter->pBwGroupR3, pBwGroupNew, PPDMNSBWGROUP);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASMAtomicWritePtr(&pFilter->pBwGroupR0, MMHyperR3ToR0(pUVM->pVM, pBwGroupNew));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pBwGroupOld)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pdmNsBwGroupUnref(pBwGroupOld);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pdmNsFilterLink(pFilter);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
19b725c530eb49600728765de7ed451cbe290740vboxsync
19b725c530eb49600728765de7ed451cbe290740vboxsync UNLOCK_NETSHAPER(pShaper);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return rc;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
19b725c530eb49600728765de7ed451cbe290740vboxsync * Detach network filter driver from bandwidth group.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pUVM The user mode VM handle.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pDrvIns The driver instance.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pFilter Pointer to the filter we detach.
19b725c530eb49600728765de7ed451cbe290740vboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncVMMR3_INT_DECL(int) PDMR3NsDetach(PUVM pUVM, PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync VM_ASSERT_EMT(pUVM->pVM);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertPtrReturn(pFilter, VERR_INVALID_POINTER);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Now, return quietly if the filter isn't attached since driver/device
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync destructors are called on constructor failure. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (!pFilter->pBwGroupR3)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertPtrReturn(pFilter->pBwGroupR3, VERR_INVALID_POINTER);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PPDMNETSHAPER pShaper = pUVM->pdm.s.pNetShaper;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LOCK_NETSHAPER_RETURN(pShaper);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
19b725c530eb49600728765de7ed451cbe290740vboxsync pdmNsFilterUnlink(pFilter);
19b725c530eb49600728765de7ed451cbe290740vboxsync PPDMNSBWGROUP pBwGroup = ASMAtomicXchgPtrT(&pFilter->pBwGroupR3, NULL, PPDMNSBWGROUP);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pBwGroup)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pdmNsBwGroupUnref(pBwGroup);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync UNLOCK_NETSHAPER(pShaper);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Adjusts the maximum rate for the bandwidth group.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
19b725c530eb49600728765de7ed451cbe290740vboxsync * @returns VBox status code.
19b725c530eb49600728765de7ed451cbe290740vboxsync * @param pUVM The user mode VM handle.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pszBwGroup Name of the bandwidth group to attach to.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param cbPerSecMax Maximum number of bytes per second to be transmitted.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncVMMR3DECL(int) PDMR3NsBwGroupSetLimit(PUVM pUVM, const char *pszBwGroup, uint64_t cbPerSecMax)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
19b725c530eb49600728765de7ed451cbe290740vboxsync UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PPDMNETSHAPER pShaper = pUVM->pdm.s.pNetShaper;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LOCK_NETSHAPER_RETURN(pShaper);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PPDMNSBWGROUP pBwGroup = pdmNsBwGroupFindById(pShaper, pszBwGroup);
19b725c530eb49600728765de7ed451cbe290740vboxsync if (pBwGroup)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PDMCritSectEnter(&pBwGroup->Lock, VERR_SEM_BUSY); AssertRC(rc);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_SUCCESS(rc))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pdmNsBwGroupSetLimit(pBwGroup, cbPerSecMax);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Drop extra tokens */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pBwGroup->cbTokensLast > pBwGroup->cbBucket)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pBwGroup->cbTokensLast = pBwGroup->cbBucket;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc2 = PDMCritSectLeave(&pBwGroup->Lock); AssertRC(rc2);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = VERR_NOT_FOUND;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync UNLOCK_NETSHAPER(pShaper);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return rc;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * I/O thread for pending TX.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VINF_SUCCESS (ignored).
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM Pointer to the VM.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pThread The PDM thread data.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic DECLCALLBACK(int) pdmR3NsTxThread(PVM pVM, PPDMTHREAD pThread)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PPDMNETSHAPER pShaper = (PPDMNETSHAPER)pThread->pvUser;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlow(("pdmR3NsTxThread: pShaper=%p\n", pShaper));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync while (pThread->enmState == PDMTHREADSTATE_RUNNING)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTThreadSleep(PDM_NETSHAPER_MAX_LATENCY);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Go over all bandwidth groups/filters calling pfnXmitPending */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LOCK_NETSHAPER(pShaper);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PPDMNSBWGROUP pBwGroup = pShaper->pBwGroupsHead;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync while (pBwGroup)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pdmNsBwGroupXmitPending(pBwGroup);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pBwGroup = pBwGroup->pNextR3;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync UNLOCK_NETSHAPER(pShaper);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @copydoc FNPDMTHREADWAKEUPINT
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic DECLCALLBACK(int) pdmR3NsTxWakeUp(PVM pVM, PPDMTHREAD pThread)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PPDMNETSHAPER pShaper = (PPDMNETSHAPER)pThread->pvUser;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlow(("pdmR3NsTxWakeUp: pShaper=%p\n", pShaper));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Nothing to do */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Terminate the network shaper.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox error code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM Pointer to VM.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @remarks This method destroys all bandwidth group objects.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncint pdmR3NetShaperTerm(PVM pVM)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PUVM pUVM = pVM->pUVM;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertPtrReturn(pUVM, VERR_INVALID_POINTER);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PPDMNETSHAPER pShaper = pUVM->pdm.s.pNetShaper;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertPtrReturn(pShaper, VERR_INVALID_POINTER);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Destroy the bandwidth managers. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PPDMNSBWGROUP pBwGroup = pShaper->pBwGroupsHead;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync while (pBwGroup)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PPDMNSBWGROUP pFree = pBwGroup;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pBwGroup = pBwGroup->pNextR3;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pdmNsBwGroupTerminate(pFree);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync MMR3HeapFree(pFree->pszNameR3);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync MMHyperFree(pVM, pFree);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTCritSectDelete(&pShaper->Lock);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Initialize the network shaper.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM Pointer to the VM.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncint pdmR3NetShaperInit(PVM pVM)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlow(("pdmR3NetShaperInit: pVM=%p\n", pVM));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync VM_ASSERT_EMT(pVM);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PUVM pUVM = pVM->pUVM;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsgReturn(!pUVM->pdm.s.pNetShaper, ("Network shaper was already initialized\n"), VERR_WRONG_ORDER);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PPDMNETSHAPER pShaper;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_NET_SHAPER, sizeof(PDMNETSHAPER), (void **)&pShaper);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_SUCCESS(rc))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PCFGMNODE pCfgNetShaper = CFGMR3GetChild(CFGMR3GetChild(CFGMR3GetRoot(pVM), "PDM"), "NetworkShaper");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pShaper->pVM = pVM;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = RTCritSectInit(&pShaper->Lock);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_SUCCESS(rc))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Create all bandwidth groups. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PCFGMNODE pCfgBwGrp = CFGMR3GetChild(pCfgNetShaper, "BwGroups");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pCfgBwGrp)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync for (PCFGMNODE pCur = CFGMR3GetFirstChild(pCfgBwGrp); pCur; pCur = CFGMR3GetNextChild(pCur))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint64_t cbMax;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync size_t cbName = CFGMR3GetNameLen(pCur) + 1;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync char *pszBwGrpId = (char *)RTMemAllocZ(cbName);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (!pszBwGrpId)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = VERR_NO_MEMORY;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = CFGMR3GetName(pCur, pszBwGrpId, cbName);
f02b41a7e54fc4e6b714f4e60260d94614d6e2e7vboxsync AssertRC(rc);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_SUCCESS(rc))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = CFGMR3QueryU64(pCur, "Max", &cbMax);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_SUCCESS(rc))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = pdmNsBwGroupCreate(pShaper, pszBwGrpId, cbMax);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTMemFree(pszBwGrpId);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_FAILURE(rc))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_SUCCESS(rc))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PDMR3ThreadCreate(pVM, &pShaper->pTxThread, pShaper, pdmR3NsTxThread, pdmR3NsTxWakeUp,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync 0 /*cbStack*/, RTTHREADTYPE_IO, "PDMNsTx");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_SUCCESS(rc))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pUVM->pdm.s.pNetShaper = pShaper;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTCritSectDelete(&pShaper->Lock);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync MMR3HeapFree(pShaper);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlow(("pdmR3NetShaperInit: pVM=%p rc=%Rrc\n", pVM, rc));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return rc;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync