VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/PDMNetShaper.cpp@ 76553

Last change on this file since 76553 was 76553, checked in by vboxsync, 5 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.9 KB
RevLine 
[40652]1/* $Id: PDMNetShaper.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
[43228]3 * PDM Network Shaper - Limit network traffic according to bandwidth group settings.
[40652]4 */
5
6/*
[76553]7 * Copyright (C) 2011-2019 Oracle Corporation
[40652]8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
[57358]19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
[40652]22#define LOG_GROUP LOG_GROUP_NET_SHAPER
23#include "PDMInternal.h"
24#include <VBox/vmm/pdm.h>
25#include <VBox/vmm/mm.h>
26#ifdef VBOX_WITH_REM
27# include <VBox/vmm/rem.h>
28#endif
29#include <VBox/vmm/vm.h>
30#include <VBox/vmm/uvm.h>
31#include <VBox/err.h>
32
33#include <VBox/log.h>
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/thread.h>
37#include <iprt/mem.h>
38#include <iprt/critsect.h>
39#include <iprt/tcp.h>
40#include <iprt/path.h>
41#include <iprt/string.h>
42
43#include <VBox/vmm/pdmnetshaper.h>
[44355]44#include "PDMNetShaperInternal.h"
[40652]45
46
[57358]47/*********************************************************************************************************************************
48* Structures and Typedefs *
49*********************************************************************************************************************************/
[40652]50
51/**
52 * Network shaper data. One instance per VM.
53 */
54typedef struct PDMNETSHAPER
55{
[41777]56 /** Pointer to the VM. */
[40652]57 PVM pVM;
58 /** Critical section protecting all members below. */
[44355]59 RTCRITSECT Lock;
[40706]60 /** Pending TX thread. */
[44355]61 PPDMTHREAD pTxThread;
[40652]62 /** Pointer to the first bandwidth group. */
63 PPDMNSBWGROUP pBwGroupsHead;
64} PDMNETSHAPER;
65
66
[44355]67/** Takes the shaper lock (asserts but doesn't return or anything on
68 * failure). */
69#define LOCK_NETSHAPER(a_pShaper) do { int rcShaper = RTCritSectEnter(&(a_pShaper)->Lock); AssertRC(rcShaper); } while (0)
[40652]70
[44355]71/** Takes the shaper lock, returns + asserts on failure. */
72#define LOCK_NETSHAPER_RETURN(a_pShaper) \
73 do { int rcShaper = RTCritSectEnter(&(a_pShaper)->Lock); AssertRCReturn(rcShaper, rcShaper); } while (0)
[40652]74
[44355]75/** Releases the shaper lock (asserts on failure). */
76#define UNLOCK_NETSHAPER(a_pShaper) do { int rcShaper = RTCritSectLeave(&(a_pShaper)->Lock); AssertRC(rcShaper); } while (0)
[43228]77
78
[44355]79
80
81static PPDMNSBWGROUP pdmNsBwGroupFindById(PPDMNETSHAPER pShaper, const char *pszId)
[40652]82{
83 PPDMNSBWGROUP pBwGroup = NULL;
84
[44355]85 if (RT_VALID_PTR(pszId))
[40652]86 {
[44355]87 LOCK_NETSHAPER(pShaper);
[40652]88
89 pBwGroup = pShaper->pBwGroupsHead;
90 while ( pBwGroup
[44355]91 && RTStrCmp(pBwGroup->pszNameR3, pszId))
92 pBwGroup = pBwGroup->pNextR3;
[40652]93
[44355]94 UNLOCK_NETSHAPER(pShaper);
[40652]95 }
96
97 return pBwGroup;
98}
99
[43228]100
[40652]101static void pdmNsBwGroupLink(PPDMNSBWGROUP pBwGroup)
102{
[44355]103 PPDMNETSHAPER pShaper = pBwGroup->pShaperR3;
104 LOCK_NETSHAPER(pShaper);
[40652]105
[44355]106 pBwGroup->pNextR3 = pShaper->pBwGroupsHead;
[40652]107 pShaper->pBwGroupsHead = pBwGroup;
108
[44355]109 UNLOCK_NETSHAPER(pShaper);
[40652]110}
111
[43228]112
[40652]113#if 0
114static void pdmNsBwGroupUnlink(PPDMNSBWGROUP pBwGroup)
115{
116 PPDMNETSHAPER pShaper = pBwGroup->pShaper;
[44355]117 LOCK_NETSHAPER(pShaper);
[40652]118
119 if (pBwGroup == pShaper->pBwGroupsHead)
120 pShaper->pBwGroupsHead = pBwGroup->pNext;
121 else
122 {
123 PPDMNSBWGROUP pPrev = pShaper->pBwGroupsHead;
124 while ( pPrev
125 && pPrev->pNext != pBwGroup)
126 pPrev = pPrev->pNext;
127
128 AssertPtr(pPrev);
129 pPrev->pNext = pBwGroup->pNext;
130 }
131
[44355]132 UNLOCK_NETSHAPER(pShaper);
[40652]133}
134#endif
135
[43228]136
[44355]137static void pdmNsBwGroupSetLimit(PPDMNSBWGROUP pBwGroup, uint64_t cbPerSecMax)
[40712]138{
[44355]139 pBwGroup->cbPerSecMax = cbPerSecMax;
140 pBwGroup->cbBucket = RT_MAX(PDM_NETSHAPER_MIN_BUCKET_SIZE, cbPerSecMax * PDM_NETSHAPER_MAX_LATENCY / 1000);
141 LogFlow(("pdmNsBwGroupSetLimit: New rate limit is %llu bytes per second, adjusted bucket size to %u bytes\n",
142 pBwGroup->cbPerSecMax, pBwGroup->cbBucket));
[40712]143}
144
[43228]145
[44355]146static int pdmNsBwGroupCreate(PPDMNETSHAPER pShaper, const char *pszBwGroup, uint64_t cbPerSecMax)
[40652]147{
[44355]148 LogFlow(("pdmNsBwGroupCreate: pShaper=%#p pszBwGroup=%#p{%s} cbPerSecMax=%llu\n", pShaper, pszBwGroup, pszBwGroup, cbPerSecMax));
[40652]149
150 AssertPtrReturn(pShaper, VERR_INVALID_POINTER);
[44355]151 AssertPtrReturn(pszBwGroup, VERR_INVALID_POINTER);
152 AssertReturn(*pszBwGroup != '\0', VERR_INVALID_PARAMETER);
[40652]153
154 int rc;
[44355]155 PPDMNSBWGROUP pBwGroup = pdmNsBwGroupFindById(pShaper, pszBwGroup);
[40652]156 if (!pBwGroup)
157 {
[42062]158 rc = MMHyperAlloc(pShaper->pVM, sizeof(PDMNSBWGROUP), 64,
159 MM_TAG_PDM_NET_SHAPER, (void **)&pBwGroup);
[40652]160 if (RT_SUCCESS(rc))
161 {
[55711]162 rc = PDMR3CritSectInit(pShaper->pVM, &pBwGroup->Lock, RT_SRC_POS, "BWGRP-%s", pszBwGroup);
[40652]163 if (RT_SUCCESS(rc))
164 {
[44355]165 pBwGroup->pszNameR3 = MMR3HeapStrDup(pShaper->pVM, MM_TAG_PDM_NET_SHAPER, pszBwGroup);
166 if (pBwGroup->pszNameR3)
[40652]167 {
[44355]168 pBwGroup->pShaperR3 = pShaper;
[40652]169 pBwGroup->cRefs = 0;
170
[44355]171 pdmNsBwGroupSetLimit(pBwGroup, cbPerSecMax);
[43228]172
[44355]173 pBwGroup->cbTokensLast = pBwGroup->cbBucket;
[40652]174 pBwGroup->tsUpdatedLast = RTTimeSystemNanoTS();
175
[44355]176 LogFlowFunc(("pszBwGroup={%s} cbBucket=%u\n",
177 pszBwGroup, pBwGroup->cbBucket));
[40652]178 pdmNsBwGroupLink(pBwGroup);
179 return VINF_SUCCESS;
180 }
[44355]181 PDMR3CritSectDelete(&pBwGroup->Lock);
[40652]182 }
[42062]183 MMHyperFree(pShaper->pVM, pBwGroup);
[40652]184 }
185 else
186 rc = VERR_NO_MEMORY;
187 }
188 else
189 rc = VERR_ALREADY_EXISTS;
190
191 LogFlowFunc(("returns rc=%Rrc\n", rc));
192 return rc;
193}
194
[43228]195
[40652]196static void pdmNsBwGroupTerminate(PPDMNSBWGROUP pBwGroup)
197{
198 Assert(pBwGroup->cRefs == 0);
[44355]199 if (PDMCritSectIsInitialized(&pBwGroup->Lock))
200 PDMR3CritSectDelete(&pBwGroup->Lock);
[40652]201}
202
203
204DECLINLINE(void) pdmNsBwGroupRef(PPDMNSBWGROUP pBwGroup)
205{
206 ASMAtomicIncU32(&pBwGroup->cRefs);
207}
208
[43228]209
[40652]210DECLINLINE(void) pdmNsBwGroupUnref(PPDMNSBWGROUP pBwGroup)
211{
212 Assert(pBwGroup->cRefs > 0);
213 ASMAtomicDecU32(&pBwGroup->cRefs);
214}
215
[43228]216
[40706]217static void pdmNsBwGroupXmitPending(PPDMNSBWGROUP pBwGroup)
218{
[41864]219 /*
220 * We don't need to hold the bandwidth group lock to iterate over the list
221 * of filters since the filters are removed while the shaper lock is being
222 * held.
223 */
224 AssertPtr(pBwGroup);
[44355]225 AssertPtr(pBwGroup->pShaperR3);
226 Assert(RTCritSectIsOwner(&pBwGroup->pShaperR3->Lock));
227 //LOCK_NETSHAPER(pShaper);
[40706]228
[41882]229 /* Check if the group is disabled. */
[44355]230 if (pBwGroup->cbPerSecMax == 0)
[41882]231 return;
232
[44355]233 PPDMNSFILTER pFilter = pBwGroup->pFiltersHeadR3;
[40706]234 while (pFilter)
235 {
236 bool fChoked = ASMAtomicXchgBool(&pFilter->fChoked, false);
[40712]237 Log3((LOG_FN_FMT ": pFilter=%#p fChoked=%RTbool\n", __PRETTY_FUNCTION__, pFilter, fChoked));
[44355]238 if (fChoked && pFilter->pIDrvNetR3)
[40706]239 {
240 LogFlowFunc(("Calling pfnXmitPending for pFilter=%#p\n", pFilter));
[44355]241 pFilter->pIDrvNetR3->pfnXmitPending(pFilter->pIDrvNetR3);
[40706]242 }
243
[44355]244 pFilter = pFilter->pNextR3;
[40706]245 }
246
[44355]247 //UNLOCK_NETSHAPER(pShaper);
[40706]248}
249
[43228]250
[40652]251static void pdmNsFilterLink(PPDMNSFILTER pFilter)
252{
253 PPDMNSBWGROUP pBwGroup = pFilter->pBwGroupR3;
[44355]254 int rc = PDMCritSectEnter(&pBwGroup->Lock, VERR_SEM_BUSY); AssertRC(rc);
[40652]255
[44355]256 pFilter->pNextR3 = pBwGroup->pFiltersHeadR3;
257 pBwGroup->pFiltersHeadR3 = pFilter;
[40652]258
[44355]259 rc = PDMCritSectLeave(&pBwGroup->Lock); AssertRC(rc);
[40652]260}
261
[43228]262
[40652]263static void pdmNsFilterUnlink(PPDMNSFILTER pFilter)
264{
265 PPDMNSBWGROUP pBwGroup = pFilter->pBwGroupR3;
[41864]266 /*
267 * We need to make sure we hold the shaper lock since pdmNsBwGroupXmitPending()
268 * does not hold the bandwidth group lock while iterating over the list
269 * of group's filters.
270 */
271 AssertPtr(pBwGroup);
[44355]272 AssertPtr(pBwGroup->pShaperR3);
273 Assert(RTCritSectIsOwner(&pBwGroup->pShaperR3->Lock));
274 int rc = PDMCritSectEnter(&pBwGroup->Lock, VERR_SEM_BUSY); AssertRC(rc);
[40652]275
[44355]276 if (pFilter == pBwGroup->pFiltersHeadR3)
277 pBwGroup->pFiltersHeadR3 = pFilter->pNextR3;
[40652]278 else
279 {
[44355]280 PPDMNSFILTER pPrev = pBwGroup->pFiltersHeadR3;
[40652]281 while ( pPrev
[44355]282 && pPrev->pNextR3 != pFilter)
283 pPrev = pPrev->pNextR3;
[40652]284
285 AssertPtr(pPrev);
[44355]286 pPrev->pNextR3 = pFilter->pNextR3;
[40652]287 }
288
[44355]289 rc = PDMCritSectLeave(&pBwGroup->Lock); AssertRC(rc);
[40652]290}
291
[43228]292
[44355]293/**
294 * Attach network filter driver from bandwidth group.
295 *
296 * @returns VBox status code.
[58126]297 * @param pUVM The user mode VM structure.
298 * @param pDrvIns The driver instance.
299 * @param pszBwGroup Name of the bandwidth group to attach to.
300 * @param pFilter Pointer to the filter we attach.
[44355]301 */
302VMMR3_INT_DECL(int) PDMR3NsAttach(PUVM pUVM, PPDMDRVINS pDrvIns, const char *pszBwGroup, PPDMNSFILTER pFilter)
[40652]303{
[44355]304 VM_ASSERT_EMT(pUVM->pVM);
[40652]305 AssertPtrReturn(pFilter, VERR_INVALID_POINTER);
306 AssertReturn(pFilter->pBwGroupR3 == NULL, VERR_ALREADY_EXISTS);
[62655]307 RT_NOREF_PV(pDrvIns);
[40652]308
309 PPDMNETSHAPER pShaper = pUVM->pdm.s.pNetShaper;
[44355]310 LOCK_NETSHAPER_RETURN(pShaper);
[40652]311
[44355]312 int rc = VINF_SUCCESS;
313 PPDMNSBWGROUP pBwGroupNew = NULL;
314 if (pszBwGroup)
315 {
316 pBwGroupNew = pdmNsBwGroupFindById(pShaper, pszBwGroup);
317 if (pBwGroupNew)
318 pdmNsBwGroupRef(pBwGroupNew);
319 else
320 rc = VERR_NOT_FOUND;
321 }
[40652]322
323 if (RT_SUCCESS(rc))
324 {
[44355]325 PPDMNSBWGROUP pBwGroupOld = ASMAtomicXchgPtrT(&pFilter->pBwGroupR3, pBwGroupNew, PPDMNSBWGROUP);
326 ASMAtomicWritePtr(&pFilter->pBwGroupR0, MMHyperR3ToR0(pUVM->pVM, pBwGroupNew));
327 if (pBwGroupOld)
328 pdmNsBwGroupUnref(pBwGroupOld);
329 pdmNsFilterLink(pFilter);
[40652]330 }
331
[44355]332 UNLOCK_NETSHAPER(pShaper);
[40652]333 return rc;
334}
335
[43228]336
[44355]337/**
338 * Detach network filter driver from bandwidth group.
339 *
340 * @returns VBox status code.
341 * @param pUVM The user mode VM handle.
342 * @param pDrvIns The driver instance.
343 * @param pFilter Pointer to the filter we detach.
344 */
345VMMR3_INT_DECL(int) PDMR3NsDetach(PUVM pUVM, PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter)
[40652]346{
[62655]347 RT_NOREF_PV(pDrvIns);
[44355]348 VM_ASSERT_EMT(pUVM->pVM);
[40652]349 AssertPtrReturn(pFilter, VERR_INVALID_POINTER);
[62655]350
[45061]351 /* Now, return quietly if the filter isn't attached since driver/device
352 destructors are called on constructor failure. */
353 if (!pFilter->pBwGroupR3)
354 return VINF_SUCCESS;
[40652]355 AssertPtrReturn(pFilter->pBwGroupR3, VERR_INVALID_POINTER);
356
357 PPDMNETSHAPER pShaper = pUVM->pdm.s.pNetShaper;
[44355]358 LOCK_NETSHAPER_RETURN(pShaper);
[40652]359
[44355]360 pdmNsFilterUnlink(pFilter);
361 PPDMNSBWGROUP pBwGroup = ASMAtomicXchgPtrT(&pFilter->pBwGroupR3, NULL, PPDMNSBWGROUP);
362 if (pBwGroup)
363 pdmNsBwGroupUnref(pBwGroup);
[40652]364
[44355]365 UNLOCK_NETSHAPER(pShaper);
366 return VINF_SUCCESS;
[40652]367}
368
[43228]369
[44355]370/**
371 * Adjusts the maximum rate for the bandwidth group.
372 *
373 * @returns VBox status code.
374 * @param pUVM The user mode VM handle.
375 * @param pszBwGroup Name of the bandwidth group to attach to.
376 * @param cbPerSecMax Maximum number of bytes per second to be transmitted.
377 */
378VMMR3DECL(int) PDMR3NsBwGroupSetLimit(PUVM pUVM, const char *pszBwGroup, uint64_t cbPerSecMax)
[40712]379{
[44355]380 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
[40712]381 PPDMNETSHAPER pShaper = pUVM->pdm.s.pNetShaper;
[44355]382 LOCK_NETSHAPER_RETURN(pShaper);
[40712]383
[44355]384 int rc;
385 PPDMNSBWGROUP pBwGroup = pdmNsBwGroupFindById(pShaper, pszBwGroup);
386 if (pBwGroup)
[40712]387 {
[44355]388 rc = PDMCritSectEnter(&pBwGroup->Lock, VERR_SEM_BUSY); AssertRC(rc);
389 if (RT_SUCCESS(rc))
[40712]390 {
[44355]391 pdmNsBwGroupSetLimit(pBwGroup, cbPerSecMax);
392
[40712]393 /* Drop extra tokens */
[44355]394 if (pBwGroup->cbTokensLast > pBwGroup->cbBucket)
395 pBwGroup->cbTokensLast = pBwGroup->cbBucket;
396
397 int rc2 = PDMCritSectLeave(&pBwGroup->Lock); AssertRC(rc2);
[40712]398 }
399 }
[44355]400 else
401 rc = VERR_NOT_FOUND;
402
403 UNLOCK_NETSHAPER(pShaper);
[40712]404 return rc;
405}
406
407
[40706]408/**
409 * I/O thread for pending TX.
410 *
411 * @returns VINF_SUCCESS (ignored).
[58122]412 * @param pVM The cross context VM structure.
[40706]413 * @param pThread The PDM thread data.
414 */
[57394]415static DECLCALLBACK(int) pdmR3NsTxThread(PVM pVM, PPDMTHREAD pThread)
[40706]416{
[62655]417 RT_NOREF_PV(pVM);
418
[40706]419 PPDMNETSHAPER pShaper = (PPDMNETSHAPER)pThread->pvUser;
420 LogFlow(("pdmR3NsTxThread: pShaper=%p\n", pShaper));
421 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
422 {
423 RTThreadSleep(PDM_NETSHAPER_MAX_LATENCY);
[44355]424
[40706]425 /* Go over all bandwidth groups/filters calling pfnXmitPending */
[44355]426 LOCK_NETSHAPER(pShaper);
[40706]427 PPDMNSBWGROUP pBwGroup = pShaper->pBwGroupsHead;
428 while (pBwGroup)
429 {
430 pdmNsBwGroupXmitPending(pBwGroup);
[44355]431 pBwGroup = pBwGroup->pNextR3;
[40706]432 }
[44355]433 UNLOCK_NETSHAPER(pShaper);
[40706]434 }
435 return VINF_SUCCESS;
436}
[40652]437
[43228]438
[40652]439/**
[40706]440 * @copydoc FNPDMTHREADWAKEUPINT
441 */
[57394]442static DECLCALLBACK(int) pdmR3NsTxWakeUp(PVM pVM, PPDMTHREAD pThread)
[40706]443{
[62655]444 RT_NOREF2(pVM, pThread);
445 LogFlow(("pdmR3NsTxWakeUp: pShaper=%p\n", pThread->pvUser));
[40706]446 /* Nothing to do */
447 return VINF_SUCCESS;
448}
449
[43228]450
[40706]451/**
[40652]452 * Terminate the network shaper.
453 *
454 * @returns VBox error code.
[58122]455 * @param pVM The cross context VM structure.
[40652]456 *
457 * @remarks This method destroys all bandwidth group objects.
458 */
459int pdmR3NetShaperTerm(PVM pVM)
460{
461 PUVM pUVM = pVM->pUVM;
[41891]462 AssertPtrReturn(pUVM, VERR_INVALID_POINTER);
[40652]463 PPDMNETSHAPER pShaper = pUVM->pdm.s.pNetShaper;
[41891]464 AssertPtrReturn(pShaper, VERR_INVALID_POINTER);
[40652]465
466 /* Destroy the bandwidth managers. */
467 PPDMNSBWGROUP pBwGroup = pShaper->pBwGroupsHead;
468 while (pBwGroup)
469 {
470 PPDMNSBWGROUP pFree = pBwGroup;
[44355]471 pBwGroup = pBwGroup->pNextR3;
[40652]472 pdmNsBwGroupTerminate(pFree);
[44355]473 MMR3HeapFree(pFree->pszNameR3);
[42062]474 MMHyperFree(pVM, pFree);
[40652]475 }
476
[44355]477 RTCritSectDelete(&pShaper->Lock);
[65719]478 MMR3HeapFree(pShaper);
479 pUVM->pdm.s.pNetShaper = NULL;
[40652]480 return VINF_SUCCESS;
481}
482
[43228]483
[40652]484/**
485 * Initialize the network shaper.
486 *
487 * @returns VBox status code
[58122]488 * @param pVM The cross context VM structure.
[40652]489 */
490int pdmR3NetShaperInit(PVM pVM)
491{
[44355]492 LogFlow(("pdmR3NetShaperInit: pVM=%p\n", pVM));
[40652]493 VM_ASSERT_EMT(pVM);
[44355]494 PUVM pUVM = pVM->pUVM;
495 AssertMsgReturn(!pUVM->pdm.s.pNetShaper, ("Network shaper was already initialized\n"), VERR_WRONG_ORDER);
[40652]496
[44355]497 PPDMNETSHAPER pShaper;
498 int rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_NET_SHAPER, sizeof(PDMNETSHAPER), (void **)&pShaper);
[40652]499 if (RT_SUCCESS(rc))
500 {
[44355]501 PCFGMNODE pCfgNetShaper = CFGMR3GetChild(CFGMR3GetChild(CFGMR3GetRoot(pVM), "PDM"), "NetworkShaper");
[40652]502
[44355]503 pShaper->pVM = pVM;
504 rc = RTCritSectInit(&pShaper->Lock);
[40652]505 if (RT_SUCCESS(rc))
506 {
507 /* Create all bandwidth groups. */
508 PCFGMNODE pCfgBwGrp = CFGMR3GetChild(pCfgNetShaper, "BwGroups");
509 if (pCfgBwGrp)
510 {
511 for (PCFGMNODE pCur = CFGMR3GetFirstChild(pCfgBwGrp); pCur; pCur = CFGMR3GetNextChild(pCur))
512 {
[43229]513 size_t cbName = CFGMR3GetNameLen(pCur) + 1;
514 char *pszBwGrpId = (char *)RTMemAllocZ(cbName);
[62655]515 if (pszBwGrpId)
[40652]516 {
[62655]517 rc = CFGMR3GetName(pCur, pszBwGrpId, cbName);
518 if (RT_SUCCESS(rc))
519 {
520 uint64_t cbMax;
521 rc = CFGMR3QueryU64(pCur, "Max", &cbMax);
522 if (RT_SUCCESS(rc))
523 rc = pdmNsBwGroupCreate(pShaper, pszBwGrpId, cbMax);
524 }
525 RTMemFree(pszBwGrpId);
526 }
527 else
[40652]528 rc = VERR_NO_MEMORY;
529 if (RT_FAILURE(rc))
530 break;
531 }
532 }
533
534 if (RT_SUCCESS(rc))
535 {
[44355]536 rc = PDMR3ThreadCreate(pVM, &pShaper->pTxThread, pShaper, pdmR3NsTxThread, pdmR3NsTxWakeUp,
537 0 /*cbStack*/, RTTHREADTYPE_IO, "PDMNsTx");
[40706]538 if (RT_SUCCESS(rc))
539 {
[44355]540 pUVM->pdm.s.pNetShaper = pShaper;
[40706]541 return VINF_SUCCESS;
542 }
[40652]543 }
544
[44355]545 RTCritSectDelete(&pShaper->Lock);
[40652]546 }
[44355]547
548 MMR3HeapFree(pShaper);
[40652]549 }
550
[44355]551 LogFlow(("pdmR3NetShaperInit: pVM=%p rc=%Rrc\n", pVM, rc));
[40652]552 return rc;
553}
554
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use